## Development lane / 开发通道 - Lane: `direct-to-main` bootstrap - Base branch: `main` - Active train: `n/a` - Owning Agent/session: workflow coordinator ## Change / 改动 - Split authoritative CI into parallel static, contract, Rust lint/test shards, Swift interaction, stress, overlay, bundle, and stable `Required CI` jobs. - Make every ready PR to `main` a complete gate while keeping task PRs to `gd-ops/train/*` path-scoped. - Add direct/train worktree coordination, bounded changelog fragments, protected main/train ruleset automation, and safe same-repository squash auto-merge. - Let GitHub Release promote an exact successful main commit, reuse its source proof, and create a missing release tag only after proof validation. - Keep local pre-push validation bounded to basic syntax, formatting, contracts, and compilation; complete duplicate proof stays in GitHub CI. This is the one bootstrap PR: the auto-merge workflow and required rules do not exist on the base branch yet. After this PR passes and is merged once, the exact `main` push must pass `Required CI`; then the fail-closed applicator can activate both rulesets and all later ready `gd-ops/*` PRs follow the automated path. ## Validation / 验证 - `actionlint .github/workflows/ci.yml .github/workflows/release.yml .github/workflows/auto-merge.yml` - `./script/validate_source_syntax.sh` - `./script/validate_build_scripts_safety.sh --skip-source-syntax` - Exact staged diff was reapplied to a clean detached worktree before the final validation run. - 28 validation-tooling tests, 40 release-distribution tests, macOS build-contract tests, Release shell contracts, and test-isolation validation passed. ## Risk / 风险 - No product runtime or credential access is added. - `pull_request_target` never checks out or executes PR code and only enables auto-merge after API verification of active PR and `Required CI` rules. - Full ruleset activation fails closed until the exact remote main commit has a trusted successful GitHub Actions push run. - Reversible repository settings are already enabled: auto-merge, squash-only, update branch, and delete merged branches. --------- Co-authored-by: gd-ops <gd-ops@xmfunny.com>
608 lines
24 KiB
YAML
608 lines
24 KiB
YAML
name: CI
|
|
|
|
on:
|
|
pull_request:
|
|
types: [opened, synchronize, reopened, ready_for_review, converted_to_draft]
|
|
push:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
APC_VALIDATE_HOST_UI: "0"
|
|
APC_VALIDATE_REAL_AGENT_CONNECTORS: "0"
|
|
APC_VALIDATE_REAL_APP_SERVER: "0"
|
|
CARGO_TERM_COLOR: always
|
|
|
|
jobs:
|
|
scope:
|
|
name: Classify change once
|
|
runs-on: macos-26
|
|
timeout-minutes: 10
|
|
outputs:
|
|
base: ${{ steps.validation_base.outputs.base }}
|
|
docs_only: ${{ steps.validation_scope.outputs.docs_only }}
|
|
localization: ${{ steps.validation_scope.outputs.localization }}
|
|
scripts: ${{ steps.validation_scope.outputs.scripts }}
|
|
producer: ${{ steps.validation_scope.outputs.producer }}
|
|
connectors: ${{ steps.validation_scope.outputs.connectors }}
|
|
schemas: ${{ steps.validation_scope.outputs.schemas }}
|
|
plugin_version: ${{ steps.validation_scope.outputs.plugin_version }}
|
|
rust_mode: ${{ steps.validation_scope.outputs.rust_mode }}
|
|
swift_mode: ${{ steps.validation_scope.outputs.swift_mode }}
|
|
bundle: ${{ steps.validation_scope.outputs.bundle }}
|
|
computer_use: ${{ steps.validation_scope.outputs.computer_use }}
|
|
lane: ${{ steps.development_context.outputs.lane }}
|
|
full_candidate: ${{ steps.development_context.outputs.full_candidate }}
|
|
release_source: ${{ steps.development_context.outputs.release_source }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Resolve validation base
|
|
id: validation_base
|
|
env:
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
PR_BASE: ${{ github.event.pull_request.base.sha }}
|
|
PUSH_BASE: ${{ github.event.before }}
|
|
run: |
|
|
if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
|
base="$PR_BASE"
|
|
else
|
|
base="$PUSH_BASE"
|
|
fi
|
|
if [[ "$base" == "0000000000000000000000000000000000000000" ]]; then
|
|
base="$(git rev-parse HEAD^ 2>/dev/null || git rev-parse HEAD)"
|
|
fi
|
|
git rev-parse --verify "$base^{commit}" >/dev/null
|
|
echo "base=$base" >>"$GITHUB_OUTPUT"
|
|
|
|
- name: Classify changed paths
|
|
id: validation_scope
|
|
run: |
|
|
./script/validation_scope.py \
|
|
--base-ref "${{ steps.validation_base.outputs.base }}" \
|
|
--format github >>"$GITHUB_OUTPUT"
|
|
|
|
- name: Resolve direct, train, and main validation lane
|
|
id: development_context
|
|
env:
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
PR_BASE_BRANCH: ${{ github.base_ref }}
|
|
PR_HEAD_BRANCH: ${{ github.head_ref }}
|
|
PR_DRAFT: ${{ github.event.pull_request.draft }}
|
|
run: |
|
|
if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
|
./script/development_flow.py ci-context \
|
|
--event pull_request \
|
|
--base "$PR_BASE_BRANCH" \
|
|
--head "$PR_HEAD_BRANCH" \
|
|
--draft "${PR_DRAFT:-false}" \
|
|
--format github >>"$GITHUB_OUTPUT"
|
|
else
|
|
./script/development_flow.py ci-context \
|
|
--event push \
|
|
--base main \
|
|
--format github >>"$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
static:
|
|
name: Static source contracts
|
|
needs: scope
|
|
runs-on: macos-26
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Install common validation tooling
|
|
run: |
|
|
if ! command -v rg >/dev/null 2>&1; then
|
|
brew install ripgrep
|
|
fi
|
|
|
|
- name: Diff and source syntax
|
|
run: |
|
|
git diff --check "${{ needs.scope.outputs.base }}" --
|
|
./script/validate_source_syntax.sh
|
|
|
|
- name: Localization parity
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.localization == '1'
|
|
run: ./script/validate_localizations.py
|
|
|
|
- name: Static workflow and build-script contracts
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.scripts == '1'
|
|
run: ./script/validate_build_scripts_safety.sh --skip-source-syntax --static-only
|
|
|
|
- name: Validate parallel changelog fragments
|
|
run: ./script/changelog_fragments.py validate
|
|
|
|
- name: Require main-bound changelog consolidation
|
|
if: >-
|
|
needs.scope.outputs.full_candidate == '1' &&
|
|
needs.scope.outputs.lane != 'task-to-train'
|
|
run: ./script/changelog_fragments.py require-consumed
|
|
|
|
- name: Codex plugin and Skill version discipline for this change
|
|
if: needs.scope.outputs.plugin_version == '1'
|
|
run: ./script/validate_codex_plugin_version.py --base-ref "${{ needs.scope.outputs.base }}"
|
|
|
|
contracts:
|
|
name: Source and integration contracts
|
|
needs: scope
|
|
if: >-
|
|
needs.scope.outputs.full_candidate == '1' ||
|
|
needs.scope.outputs.docs_only != '1'
|
|
runs-on: macos-26
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Install common validation tooling
|
|
run: |
|
|
if ! command -v rg >/dev/null 2>&1; then
|
|
brew install ripgrep
|
|
fi
|
|
|
|
- name: Prepare pinned Python validation environment
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.producer == '1' || needs.scope.outputs.bundle == '1'
|
|
run: |
|
|
python3 -m venv "$RUNNER_TEMP/apc-validation-python"
|
|
"$RUNNER_TEMP/apc-validation-python/bin/python" -m pip install \
|
|
--disable-pip-version-check --no-deps --only-binary=:all: "Pillow==11.3.0"
|
|
"$RUNNER_TEMP/apc-validation-python/bin/python" - <<'PY'
|
|
from PIL import Image, features
|
|
if Image.__version__ != "11.3.0" or not features.check("webp_anim"):
|
|
raise SystemExit("pinned Pillow lacks the required animated WebP support")
|
|
PY
|
|
echo "$RUNNER_TEMP/apc-validation-python/bin" >>"$GITHUB_PATH"
|
|
|
|
- name: Restore contract build products
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: ${{ runner.os }}-${{ runner.arch }}-apc-contracts-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ runner.arch }}-apc-contracts-
|
|
${{ runner.os }}-${{ runner.arch }}-apc-rust-
|
|
|
|
- name: Complete build and workflow contracts
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.scripts == '1'
|
|
run: ./script/validate_build_scripts_safety.sh --skip-source-syntax
|
|
|
|
- name: App lifecycle contract
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.swift_mode != 'none'
|
|
run: ./script/validate_app_lifecycle_contract.sh
|
|
|
|
- name: Schema contracts
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.schemas == '1' || needs.scope.outputs.producer == '1'
|
|
run: |
|
|
./script/validate_schema_fixtures.sh
|
|
./script/validate_petpack_spec_schemas.sh
|
|
|
|
- name: Portable producer contracts
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.producer == '1'
|
|
run: |
|
|
./script/validate_pet_skills.sh
|
|
./script/validate_portable_pet_maker.sh
|
|
|
|
- name: Generated connector runtime
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.connectors == '1'
|
|
run: ./script/validate_connectors_runtime.sh
|
|
|
|
- name: Security boundaries
|
|
if: >-
|
|
needs.scope.outputs.full_candidate == '1' ||
|
|
needs.scope.outputs.rust_mode != 'none' ||
|
|
needs.scope.outputs.schemas == '1' ||
|
|
needs.scope.outputs.producer == '1' ||
|
|
needs.scope.outputs.connectors == '1'
|
|
run: ./script/validate_security_boundaries.sh
|
|
|
|
rust_lint:
|
|
name: Rust formatting and linting
|
|
needs: scope
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.rust_mode != 'none'
|
|
runs-on: macos-26
|
|
timeout-minutes: 20
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
|
|
- name: Verify Rust toolchain
|
|
run: rustup show
|
|
|
|
- name: Restore Rust lint cache
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: ${{ runner.os }}-${{ runner.arch }}-apc-rust-lint-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ runner.arch }}-apc-rust-
|
|
|
|
- name: Rust formatting
|
|
run: cargo fmt --all -- --check
|
|
|
|
- name: Strict Rust linting
|
|
run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
|
|
|
|
rust_tests:
|
|
name: Rust tests (${{ matrix.shard }})
|
|
needs: scope
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.rust_mode != 'none'
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
shard: [core, integration-a, integration-b, integration-c, integration-d]
|
|
runs-on: macos-26
|
|
timeout-minutes: 25
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
|
|
- name: Verify Rust toolchain
|
|
run: rustup show
|
|
|
|
- name: Restore Rust test cache
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: ${{ runner.os }}-${{ runner.arch }}-apc-rust-${{ matrix.shard }}-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ runner.arch }}-apc-rust-${{ matrix.shard }}-
|
|
${{ runner.os }}-${{ runner.arch }}-apc-rust-
|
|
|
|
- name: Run inventory-checked Rust shard
|
|
run: ./script/validate_rust_test_shards.py --shard "${{ matrix.shard }}"
|
|
|
|
swift_interaction:
|
|
name: Swift and interaction proof
|
|
needs: scope
|
|
if: needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.bundle == '1' || needs.scope.outputs.swift_mode != 'none'
|
|
runs-on: macos-26
|
|
timeout-minutes: 25
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
|
|
- name: Verify App build toolchain
|
|
run: ./script/validate_macos_build_contract.py toolchain
|
|
|
|
- name: Restore Swift build products
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: apps/macos/.build
|
|
key: ${{ runner.os }}-${{ runner.arch }}-apc-swift-${{ hashFiles('apps/macos/Package.swift', 'apps/macos/Package.resolved') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ runner.arch }}-apc-swift-
|
|
|
|
- name: Run complete Swift suite and create source interaction proof
|
|
env:
|
|
APC_BUILD_ID: source.${{ github.sha }}
|
|
run: |
|
|
./script/prepare_interaction_attestation.sh \
|
|
--output "$RUNNER_TEMP/interaction-attestation.json" \
|
|
--swift-scope all
|
|
|
|
- name: Upload source interaction proof
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: ci-interaction-attestation-${{ github.sha }}
|
|
if-no-files-found: error
|
|
retention-days: 3
|
|
path: ${{ runner.temp }}/interaction-attestation.json
|
|
|
|
stress:
|
|
name: Bounded event-storm stress
|
|
needs: scope
|
|
if: needs.scope.outputs.full_candidate == '1'
|
|
runs-on: macos-26
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
|
|
- name: Restore Rust stress cache
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: ${{ runner.os }}-${{ runner.arch }}-apc-rust-stress-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ runner.arch }}-apc-rust-
|
|
|
|
- name: Run release-grade bounded event storm
|
|
run: ./script/validate_event_storm.sh
|
|
|
|
overlay:
|
|
name: Offline overlay contracts
|
|
needs: [scope, swift_interaction]
|
|
if: >-
|
|
always() &&
|
|
(needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.bundle == '1' || needs.scope.outputs.swift_mode != 'none') &&
|
|
needs.swift_interaction.result == 'success'
|
|
runs-on: macos-26
|
|
timeout-minutes: 20
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: ci-interaction-attestation-${{ github.sha }}
|
|
path: ${{ runner.temp }}/interaction-proof
|
|
|
|
- name: Restore Swift build products
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: apps/macos/.build
|
|
key: ${{ runner.os }}-${{ runner.arch }}-apc-swift-${{ hashFiles('apps/macos/Package.swift', 'apps/macos/Package.resolved') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ runner.arch }}-apc-swift-
|
|
|
|
- name: Run offline overlay geometry, scheduler, accessibility, frame, and pointer contracts
|
|
run: |
|
|
./script/validate_overlay_offline.sh \
|
|
--interaction-attestation "$RUNNER_TEMP/interaction-proof/interaction-attestation.json"
|
|
|
|
bundle:
|
|
name: Packaged development App proof
|
|
needs: [scope, contracts, rust_lint, rust_tests, swift_interaction, overlay]
|
|
if: >-
|
|
always() &&
|
|
(needs.scope.outputs.full_candidate == '1' || needs.scope.outputs.bundle == '1')
|
|
runs-on: macos-26
|
|
timeout-minutes: 30
|
|
steps:
|
|
- name: Require successful source dependencies
|
|
env:
|
|
CONTRACTS_RESULT: ${{ needs.contracts.result }}
|
|
RUST_LINT_RESULT: ${{ needs.rust_lint.result }}
|
|
RUST_TESTS_RESULT: ${{ needs.rust_tests.result }}
|
|
SWIFT_RESULT: ${{ needs.swift_interaction.result }}
|
|
OVERLAY_RESULT: ${{ needs.overlay.result }}
|
|
run: |
|
|
for result in "$CONTRACTS_RESULT" "$RUST_LINT_RESULT" "$RUST_TESTS_RESULT" "$SWIFT_RESULT" "$OVERLAY_RESULT"; do
|
|
case "$result" in
|
|
success|skipped) ;;
|
|
*) echo "bundle dependency did not succeed: $result" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
test "$SWIFT_RESULT" = "success"
|
|
test "$OVERLAY_RESULT" = "success"
|
|
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: ci-interaction-attestation-${{ github.sha }}
|
|
path: ${{ runner.temp }}/interaction-proof
|
|
|
|
- name: Rebind source interaction proof to the development build identity
|
|
id: development_identity
|
|
run: |
|
|
version="$(awk -F'"' '/^version = / {print $2; exit}' crates/petcore/Cargo.toml)"
|
|
variant="debug|$(uname -m)|universal=0|signed=1"
|
|
fingerprint="$(
|
|
./script/validation_fingerprint.py \
|
|
--root "$GITHUB_WORKSPACE" \
|
|
--scope runtime \
|
|
--extra "$variant"
|
|
)"
|
|
build_id="$version.1.develop.${fingerprint:0:16}"
|
|
APC_BUILD_ID="$build_id" \
|
|
./script/prepare_interaction_attestation.sh \
|
|
--output "$RUNNER_TEMP/interaction-proof/development-attestation.json" \
|
|
--proof-in "$RUNNER_TEMP/interaction-proof/interaction-attestation.json"
|
|
echo "build_id=$build_id" >>"$GITHUB_OUTPUT"
|
|
|
|
- name: Prepare pinned Python validation environment
|
|
run: |
|
|
python3 -m venv "$RUNNER_TEMP/apc-validation-python"
|
|
"$RUNNER_TEMP/apc-validation-python/bin/python" -m pip install \
|
|
--disable-pip-version-check --no-deps --only-binary=:all: "Pillow==11.3.0"
|
|
echo "$RUNNER_TEMP/apc-validation-python/bin" >>"$GITHUB_PATH"
|
|
|
|
- name: Restore Rust build products
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
target
|
|
key: ${{ runner.os }}-${{ runner.arch }}-apc-rust-bundle-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ runner.arch }}-apc-rust-
|
|
|
|
- name: Restore Swift build products
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: apps/macos/.build
|
|
key: ${{ runner.os }}-${{ runner.arch }}-apc-swift-${{ hashFiles('apps/macos/Package.swift', 'apps/macos/Package.resolved') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ runner.arch }}-apc-swift-
|
|
|
|
- name: Build and fully validate development App from the proven interaction contract
|
|
env:
|
|
APC_BUILD_ID: ${{ steps.development_identity.outputs.build_id }}
|
|
run: |
|
|
./script/build_app_bundle.sh \
|
|
--configuration debug \
|
|
--interaction-attestation "$RUNNER_TEMP/interaction-proof/development-attestation.json" \
|
|
--validation full
|
|
|
|
source_proof:
|
|
name: Bind release source proof to main commit
|
|
needs: [scope, static, contracts, rust_lint, rust_tests, swift_interaction, stress, overlay, bundle]
|
|
if: always() && needs.scope.outputs.release_source == '1'
|
|
runs-on: macos-26
|
|
timeout-minutes: 15
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
steps:
|
|
- name: Require every release source gate
|
|
env:
|
|
STATIC_RESULT: ${{ needs.static.result }}
|
|
CONTRACTS_RESULT: ${{ needs.contracts.result }}
|
|
RUST_LINT_RESULT: ${{ needs.rust_lint.result }}
|
|
RUST_TESTS_RESULT: ${{ needs.rust_tests.result }}
|
|
SWIFT_RESULT: ${{ needs.swift_interaction.result }}
|
|
STRESS_RESULT: ${{ needs.stress.result }}
|
|
OVERLAY_RESULT: ${{ needs.overlay.result }}
|
|
BUNDLE_RESULT: ${{ needs.bundle.result }}
|
|
run: |
|
|
for result in "$STATIC_RESULT" "$CONTRACTS_RESULT" "$RUST_LINT_RESULT" "$RUST_TESTS_RESULT" "$SWIFT_RESULT" "$STRESS_RESULT" "$OVERLAY_RESULT" "$BUNDLE_RESULT"; do
|
|
case "$result" in
|
|
success) ;;
|
|
*) echo "release source dependency did not succeed: $result" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: ci-interaction-attestation-${{ github.sha }}
|
|
path: ${{ runner.temp }}/interaction-proof
|
|
|
|
- name: Verify and record proof-host toolchains
|
|
run: ./script/validate_macos_build_contract.py toolchain
|
|
|
|
- name: Resolve latest stable release baseline
|
|
id: release_baseline
|
|
run: |
|
|
previous_tag="$(
|
|
gh api \
|
|
-H 'Accept: application/vnd.github+json' \
|
|
-H 'X-GitHub-Api-Version: 2026-03-10' \
|
|
"repos/$GITHUB_REPOSITORY/releases/latest" \
|
|
--jq '.tag_name'
|
|
)"
|
|
[[ "$previous_tag" =~ ^v[0-9]+[.][0-9]+[.][0-9]+$ ]]
|
|
echo "previous_tag=$previous_tag" >>"$GITHUB_OUTPUT"
|
|
|
|
- name: Recheck Codex plugin and bundled Skill version discipline
|
|
run: ./script/validate_codex_plugin_version.py --base-ref "${{ steps.release_baseline.outputs.previous_tag }}"
|
|
|
|
- name: Create exact-commit source proof
|
|
run: |
|
|
mkdir -p "$RUNNER_TEMP/release-source-proof"
|
|
cp "$RUNNER_TEMP/interaction-proof/interaction-attestation.json" \
|
|
"$RUNNER_TEMP/release-source-proof/interaction-attestation.json"
|
|
./script/release_source_proof.py create \
|
|
--repository "$GITHUB_REPOSITORY" \
|
|
--commit "$GITHUB_SHA" \
|
|
--previous-release-tag "${{ steps.release_baseline.outputs.previous_tag }}" \
|
|
--run-id "$GITHUB_RUN_ID" \
|
|
--run-attempt "$GITHUB_RUN_ATTEMPT" \
|
|
--attestation "$RUNNER_TEMP/release-source-proof/interaction-attestation.json" \
|
|
--output "$RUNNER_TEMP/release-source-proof/source-proof.json"
|
|
|
|
- name: Upload exact-commit release source proof
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: release-source-proof-${{ github.sha }}
|
|
if-no-files-found: error
|
|
retention-days: 7
|
|
path: ${{ runner.temp }}/release-source-proof
|
|
|
|
required:
|
|
name: Required CI
|
|
needs: [scope, static, contracts, rust_lint, rust_tests, swift_interaction, stress, overlay, bundle, source_proof]
|
|
if: always()
|
|
runs-on: macos-26
|
|
timeout-minutes: 10
|
|
steps:
|
|
- name: Require every scheduled job
|
|
env:
|
|
SCOPE_RESULT: ${{ needs.scope.result }}
|
|
STATIC_RESULT: ${{ needs.static.result }}
|
|
CONTRACTS_RESULT: ${{ needs.contracts.result }}
|
|
RUST_LINT_RESULT: ${{ needs.rust_lint.result }}
|
|
RUST_TESTS_RESULT: ${{ needs.rust_tests.result }}
|
|
SWIFT_RESULT: ${{ needs.swift_interaction.result }}
|
|
STRESS_RESULT: ${{ needs.stress.result }}
|
|
OVERLAY_RESULT: ${{ needs.overlay.result }}
|
|
BUNDLE_RESULT: ${{ needs.bundle.result }}
|
|
SOURCE_PROOF_RESULT: ${{ needs.source_proof.result }}
|
|
FULL_CANDIDATE: ${{ needs.scope.outputs.full_candidate }}
|
|
RELEASE_SOURCE: ${{ needs.scope.outputs.release_source }}
|
|
run: |
|
|
for result in \
|
|
"$SCOPE_RESULT" "$STATIC_RESULT" "$CONTRACTS_RESULT" \
|
|
"$RUST_LINT_RESULT" "$RUST_TESTS_RESULT" "$SWIFT_RESULT" \
|
|
"$STRESS_RESULT" "$OVERLAY_RESULT" "$BUNDLE_RESULT" "$SOURCE_PROOF_RESULT"; do
|
|
case "$result" in
|
|
success|skipped) ;;
|
|
*) echo "scheduled CI job did not succeed: $result" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
if [[ "$FULL_CANDIDATE" == "1" ]]; then
|
|
for result in \
|
|
"$STATIC_RESULT" "$CONTRACTS_RESULT" "$RUST_LINT_RESULT" \
|
|
"$RUST_TESTS_RESULT" "$SWIFT_RESULT" "$STRESS_RESULT" \
|
|
"$OVERLAY_RESULT" "$BUNDLE_RESULT"; do
|
|
case "$result" in
|
|
success) ;;
|
|
*) echo "complete main-bound job did not succeed: $result" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
fi
|
|
if [[ "$RELEASE_SOURCE" == "1" ]]; then
|
|
test "$SOURCE_PROOF_RESULT" = "success"
|
|
fi
|
|
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
|
|
- name: Record live UI validation routing
|
|
env:
|
|
DEVELOPMENT_LANE: ${{ needs.scope.outputs.lane }}
|
|
run: |
|
|
printf 'Development lane: %s.\n' "$DEVELOPMENT_LANE" >>"$GITHUB_STEP_SUMMARY"
|
|
if [[ "${{ needs.scope.outputs.full_candidate }}" == "1" ]]; then
|
|
echo 'This is a complete main-bound candidate gate.' >>"$GITHUB_STEP_SUMMARY"
|
|
else
|
|
echo 'This is a change-scoped task-to-train or draft gate.' >>"$GITHUB_STEP_SUMMARY"
|
|
fi
|
|
if [[ "${{ needs.scope.outputs.computer_use }}" == "recommended" ]]; then
|
|
echo 'UI source changed: Computer Use is recommended for a human-owned acceptance session, but is never auto-run in CI.' >>"$GITHUB_STEP_SUMMARY"
|
|
else
|
|
echo 'No live UI or Computer Use validation is required for this change scope.' >>"$GITHUB_STEP_SUMMARY"
|
|
fi
|
|
|
|
- name: Reject tracked build output and caches
|
|
run: |
|
|
tracked_generated="$(
|
|
git ls-files \
|
|
| grep -E '(^|/)(__pycache__/|[^/]+\.py[co]$|DerivedData/|target/|\.build/|[^/]+\.petpack$|generation-jobs/)' \
|
|
| grep -Ev '^apps/macos/Sources/AgentPetCompanion/Resources/BuiltInPets/(pet_bytebudcodex|pet_pinklace|pet_xingwutuanzi)\.petpack$' \
|
|
|| true
|
|
)"
|
|
if [[ -n "$tracked_generated" ]]; then
|
|
printf '%s\n' "$tracked_generated"
|
|
echo 'Tracked generated output or cache detected' >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Verify clean generated state
|
|
run: git diff --check
|