diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3873fb4a9..069adb654 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,509 +1,27 @@ -name: CI - +name: Native Windows application fixture verification on: - push: - branches: [main] - pull_request: - branches: [main, "release/*"] - schedule: - - cron: "23 0-2,4-23 * * *" - - cron: "23 3 * * *" workflow_dispatch: - workflow_call: - inputs: - source_sha: - description: Exact qualification source; must match the caller revision. - required: true - type: string - permissions: contents: read - concurrency: - # Complete qualification finishes even while main receives more pushes. - # Main feedback also finishes, coalescing newer pushes to one pending run. - # Scheduled/manual main runs coalesce to one active and the latest pending; - # release and label-triggered qualification use exact-revision groups. - group: ci-${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || inputs.source_sha != '' || contains(github.event.pull_request.labels.*.name, 'ci:full')) && 'qualification' || 'feedback' }}-${{ inputs.source_sha || github.event.pull_request.number || github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' && inputs.source_sha == '' && !contains(github.event.pull_request.labels.*.name, 'ci:full') }} - + group: native-windows-fixture-proof-${{ github.ref }} + cancel-in-progress: false env: HUSKY: "0" - + NODE_OPTIONS: --max-old-space-size=1536 + PROOF_SOURCE: 011be9c3d51a546fa6616145173e4c77b2d103f0 + PROOF_BASE: 5b16f2431062eea6ffd245a9e05512790007cb13 jobs: - changes: - name: Classify changes - runs-on: ubuntu-24.04 - timeout-minutes: 5 - permissions: - contents: read - actions: read - outputs: - tier: ${{ steps.plan.outputs.tier }} - qualification_run_id: ${{ steps.qualification.outputs.run_id }} - code: ${{ steps.plan.outputs.code }} - reverse_tools: ${{ steps.plan.outputs.reverse_tools }} - sqlite: ${{ steps.plan.outputs.sqlite }} - runtime: ${{ steps.plan.outputs.runtime }} - package: ${{ steps.plan.outputs.package }} - apple: ${{ steps.plan.outputs.apple }} - fixtures: ${{ steps.plan.outputs.fixtures }} - readiness: ${{ steps.plan.outputs.readiness }} - docs: ${{ steps.plan.outputs.docs }} - workflows: ${{ steps.plan.outputs.workflows }} - browser: ${{ steps.plan.outputs.browser }} - binary_layout: ${{ steps.plan.outputs.binary_layout }} - evm: ${{ steps.plan.outputs.evm }} - javascript_recovery: ${{ steps.plan.outputs.javascript_recovery }} - recorded_crash: ${{ steps.plan.outputs.recorded_crash }} - web_network: ${{ steps.plan.outputs.web_network }} - web_runtime: ${{ steps.plan.outputs.web_runtime }} - web_source_map: ${{ steps.plan.outputs.web_source_map }} - nativeaot: ${{ steps.plan.outputs.nativeaot }} - website: ${{ steps.plan.outputs.website }} - matrix: ${{ steps.plan.outputs.matrix }} - test_selection: ${{ steps.plan.outputs.test_selection }} - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - with: - ref: ${{ inputs.source_sha || github.sha }} - fetch-depth: 0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Bind qualification to the caller revision - if: inputs.source_sha != '' - env: - SOURCE_SHA: ${{ inputs.source_sha }} - run: | - test "${SOURCE_SHA}" = "${GITHUB_SHA}" - test "${SOURCE_SHA}" = "$(git rev-parse HEAD)" - - name: Find a verified ancestor for push selection - id: baseline - if: github.event_name == 'push' && inputs.source_sha == '' - env: - GH_TOKEN: ${{ github.token }} - HEAD_SHA: ${{ github.sha }} - CI_REPOSITORY: ${{ github.repository }} - CI_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - run: node scripts/ci/baseline.mjs - - name: Admit scheduled full qualification - id: qualification - if: github.event_name == 'schedule' && inputs.source_sha == '' - env: - GH_TOKEN: ${{ github.token }} - HEAD_SHA: ${{ github.sha }} - CI_REPOSITORY: ${{ github.repository }} - CI_REPOSITORY_ID: ${{ github.repository_id }} - CI_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - CI_FORCE_FULL: ${{ github.event.schedule == '23 3 * * *' }} - run: node scripts/ci/qualification.mjs - - name: Select verification lanes - id: plan - env: - BASE_SHA: ${{ steps.baseline.outputs.base || github.event.pull_request.base.sha }} - BASELINE_REASON: ${{ steps.baseline.outputs.reason }} - HEAD_SHA: ${{ inputs.source_sha || github.event.pull_request.head.sha || github.sha }} - CI_FULL: ${{ inputs.source_sha != '' || contains(github.event.pull_request.labels.*.name, 'ci:full') }} - CI_SKIP_FULL: ${{ steps.qualification.outputs.run_full == 'false' }} - run: node scripts/ci/plan.mjs - - static: - name: Static checks - needs: changes - if: ${{ !cancelled() && needs.changes.outputs.tier != 'reused' }} + native-build: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - name: Require successful change classification - env: - CHANGES_RESULT: ${{ needs.changes.result }} - run: test "${CHANGES_RESULT}" = "success" - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - run: npm ci - - name: Restore static task cache - if: needs.changes.outputs.code == 'true' - id: static-cache - uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: .turbo/cache/ - key: rea-static-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.nvmrc', '.npmrc', 'package-lock.json') }}-${{ github.sha }} - # Turbo validates each task's inputs after restoring this snapshot. - restore-keys: rea-static-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.nvmrc', '.npmrc', 'package-lock.json') }}- - - name: Validate workflow syntax and expressions - if: needs.changes.outputs.workflows == 'true' - run: go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.7 -shellcheck= -pyflakes= - - name: Record static task source and execution identity - continue-on-error: true - if: needs.changes.outputs.code == 'true' - env: - CI_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - run: npm run ci:static-context - - if: needs.changes.outputs.code == 'true' - run: npm run check:ci - - if: needs.changes.outputs.code == 'true' - run: npm run verify:test-discovery - - name: Check LLDB producer retention and launch contracts - if: needs.changes.outputs.code == 'true' - run: npm run test:python - - if: needs.changes.outputs.code != 'true' - run: npm run format:check - - name: Save validated static task cache - if: >- - success() && needs.changes.outputs.code == 'true' && - steps.npm-cache.outputs.can-save == 'true' && - steps.static-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: .turbo/cache/ - key: ${{ steps.static-cache.outputs.cache-primary-key }} - - name: Upload complete static diagnostics - if: always() && needs.changes.outputs.code == 'true' - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: static-check-reports - path: .cache/static-checks/ - include-hidden-files: true - if-no-files-found: ignore - retention-days: 7 - - test-source: - name: Source tests - needs: changes - if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tier == 'fast' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - run: npm ci - - name: Run source tests without waiting for build - run: npm run test:fast -- --reporter=default --reporter=blob - env: - VITEST_BLOB_LABEL: source - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - if: ${{ !cancelled() }} - with: - name: vitest-report-source - path: .vitest/blob/* - include-hidden-files: true - if-no-files-found: error - retention-days: 7 - - test-shard: - name: Test shard (${{ matrix.shard }}) - needs: [changes, build] - if: needs.changes.outputs.code == 'true' - runs-on: ubuntu-latest - timeout-minutes: 30 - strategy: - # Failed PRs release the remaining matrix slots; qualification retains - # every shard's diagnostics and coverage. Passing PRs run the full suite. - fail-fast: ${{ github.event_name == 'pull_request' && needs.changes.outputs.tier == 'fast' }} - matrix: - # Fast feedback spends the same six test jobs on one source group and - # five built groups; full qualification retains six complete shards. - shard: ${{ fromJSON(needs.changes.outputs.tier == 'fast' && '["1/5","2/5","3/5","4/5","5/5"]' || '["1/6","2/6","3/6","4/6","5/6","6/6"]') }} - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - run: npm ci - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: rea-test-runtime - path: . - - name: Run complete portable suite with coverage - if: needs.changes.outputs.tier == 'full' - run: npm run test:ci:shard:run -- --shard=${{ matrix.shard }} - env: - REA_CI_TEST_HISTORY: .cache/ci-test-history/test-results.json - - name: Run built-dependent tests for fast feedback - if: needs.changes.outputs.tier == 'fast' - run: npm run test:built -- --reporter=default --reporter=blob --shard=${{ matrix.shard }} - env: - VITEST_BLOB_LABEL: built - REA_CI_TEST_HISTORY: .cache/ci-test-history/test-results.json - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - if: ${{ !cancelled() }} - with: - name: vitest-report-built-${{ strategy.job-index }} - path: .vitest/blob/* - include-hidden-files: true - if-no-files-found: error - overwrite: true - retention-days: 7 - - reverse-tools-quality: - name: Reverse tools quality - needs: [changes, static] - if: needs.changes.outputs.reverse_tools == 'true' - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - run: npm ci - - name: Run reverse tools tests with coverage - run: npm run test:coverage:reverse-tools - - name: Preflight both reverse tools mutation configurations - run: | - node scripts/prepare-reverse-tools-mutation.mjs - npx --no-install stryker run stryker.config.mjs --dryRunOnly - npx --no-install stryker run stryker.semantics.config.mjs --dryRunOnly - - name: Retain available reverse tools diagnostics - if: ${{ !cancelled() }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: reverse-tools-quality-${{ needs.changes.outputs.tier }}-${{ github.run_attempt }} - path: | - coverage/reverse-tools/ - reports/mutation/ - if-no-files-found: warn - retention-days: 7 - - build: - name: Build package - needs: changes - # Reusable provider workflows consume this run's portable build artifact, - # even when a workflow-only edit selects the lane without portable tests. - if: >- - needs.changes.outputs.code == 'true' || - needs.changes.outputs.browser == 'true' || - needs.changes.outputs.binary_layout == 'true' || - needs.changes.outputs.evm == 'true' || - needs.changes.outputs.javascript_recovery == 'true' || - needs.changes.outputs.recorded_crash == 'true' || - needs.changes.outputs.web_network == 'true' || - needs.changes.outputs.web_runtime == 'true' || - needs.changes.outputs.web_source_map == 'true' - runs-on: ubuntu-latest - timeout-minutes: 10 - permissions: - contents: read - actions: read - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - run: npm ci - - name: Reuse portable build outputs across runs - uses: ./.github/actions/portable-build-cache - with: - save: ${{ github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} - - run: npm run test:prepare - - name: Find available trusted full-suite timing history - id: history - continue-on-error: true - env: - GH_TOKEN: ${{ github.token }} - CI_REPOSITORY: ${{ github.repository }} - CI_REPOSITORY_ID: ${{ github.repository_id }} - CI_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - run: node scripts/ci/test-history.mjs - - name: Download previous timing report - if: steps.history.outputs.run-id != '' - continue-on-error: true - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: test-timings - run-id: ${{ steps.history.outputs.run-id }} - github-token: ${{ github.token }} - path: .cache/ci-test-history - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: rea-test-runtime - path: | - dist/ - skills/ - .cache/mcp-tool-catalog.json - .cache/ci-test-history/test-results.json - docs/public/product-catalog.json - docs/verification/managed-conformance-*.json - include-hidden-files: true - if-no-files-found: error - retention-days: 7 - - # test:prepare caches only portable JS, skill, and catalog outputs. - # Native package jobs still run their build and prepack checks; Turbo - # restores matching outputs or rebuilds when their inputs differ. - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: rea-build-cache - path: .turbo/cache/ - include-hidden-files: true - if-no-files-found: error - retention-days: 7 - - sqlite-runtime: - # Preserve all selected coverage, but admit expensive host/provider work - # only after static validation. Portable tests still provide early feedback. - needs: [changes, static, build] - if: needs.changes.outputs.sqlite == 'true' - uses: ./.github/workflows/sqlite-runtime.yml - - test: - name: Portable tests - needs: [changes, test-source, test-shard] - if: ${{ !cancelled() && needs.changes.outputs.tier != 'reused' }} - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Require successful change classification - env: - CHANGES_RESULT: ${{ needs.changes.result }} - run: test "${CHANGES_RESULT}" = "success" - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - if: needs.changes.outputs.code == 'true' && success() - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - if: needs.changes.outputs.code == 'true' && success() - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - if: needs.changes.outputs.code == 'true' && success() - id: npm-cache - uses: ./.github/actions/npm-cache - - if: needs.changes.outputs.code == 'true' && success() - run: npm ci - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - if: >- - !cancelled() && needs.changes.outputs.code == 'true' && - (needs.test-shard.result == 'success' || needs.test-shard.result == 'failure' || - (needs.changes.outputs.tier == 'fast' && - (needs.test-source.result == 'success' || needs.test-source.result == 'failure'))) - with: - path: .vitest/blob - pattern: vitest-report-* - merge-multiple: true - - name: Merge coverage, JUnit, and timing reports - id: merge - if: >- - !cancelled() && needs.changes.outputs.code == 'true' && - needs.changes.outputs.tier == 'full' && - (needs.test-shard.result == 'success' || needs.test-shard.result == 'failure') - run: >- - npm run test:ci:merge -- - --coverage.reportsDirectory=coverage - --coverage.reporter=text - --coverage.reporter=json-summary - --coverage.reporter=lcov - --reporter=default - --reporter=junit - --reporter=json - --reporter=./scripts/ci/test-timing-reporter.mjs - --outputFile.junit=test-results.xml - --outputFile.json=test-results.json - - name: Merge fast-suite JUnit and timing reports - id: merge-fast - if: >- - !cancelled() && needs.changes.outputs.code == 'true' && - needs.changes.outputs.tier == 'fast' && - (needs.test-shard.result == 'success' || needs.test-shard.result == 'failure' || - needs.test-source.result == 'success' || needs.test-source.result == 'failure') - run: >- - npm exec -- vitest --merge-reports - --reporter=default - --reporter=junit - --reporter=json - --reporter=./scripts/ci/test-timing-reporter.mjs - --outputFile.junit=test-results.xml - --outputFile.json=test-results.json - - name: Summarize slowest test files - if: needs.changes.outputs.code == 'true' && !cancelled() - env: - SHARD_RESULT: ${{ needs.test-shard.result }} - SOURCE_REQUIRED: ${{ needs.changes.outputs.tier == 'fast' }} - SOURCE_RESULT: ${{ needs.test-source.result }} - MERGE_RESULT: ${{ needs.changes.outputs.tier == 'full' && steps.merge.outcome || steps.merge-fast.outcome }} - CI_VERIFY_TEST_INVENTORY: "true" - CI_TEST_SELECTION: ${{ needs.changes.outputs.test_selection }} - CI_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - run: node scripts/ci/test-report.mjs - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - if: needs.changes.outputs.code == 'true' && !cancelled() && hashFiles('test-results.json') != '' - with: - name: test-results - path: | - test-results.xml - test-results.json - test-timings.json - coverage/ - .cache/ci-test-selection/report.json - include-hidden-files: true - if-no-files-found: error - retention-days: 30 - - name: Publish successful timing history - if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tier == 'full' && success() && needs.test-shard.result == 'success' - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: test-timings - path: .cache/ci-test-history/test-results.json - include-hidden-files: true - if-no-files-found: error - retention-days: 30 - - name: Require successful test shards - if: ${{ !cancelled() }} - env: - CODE_REQUIRED: ${{ needs.changes.outputs.code }} - SHARD_RESULT: ${{ needs.test-shard.result }} - SOURCE_REQUIRED: ${{ needs.changes.outputs.tier == 'fast' }} - SOURCE_RESULT: ${{ needs.test-source.result }} - run: | - if [ "${CODE_REQUIRED}" = "true" ]; then - test "${SHARD_RESULT}" = "success" || exit 1 - test "${SOURCE_REQUIRED}" != "true" || test "${SOURCE_RESULT}" = "success" - fi - - conformance-fixtures: - name: Source-built conformance fixtures - needs: [changes, static] - if: needs.changes.outputs.fixtures == 'true' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - name: Verify fixtures from a clean checkout - run: npm run verify:fixtures - - windows-native-build: - name: Build bundled Windows x64 native controls - needs: [changes, static] - if: needs.changes.outputs.runtime == 'true' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version-file: .nvmrc - name: Prepare cross compiler run: | - # Slow Azure archive transfers can exhaust the job before compilation. - # Keep the same signed packages and avoid slow HTTP mirror fallback. for source in /etc/apt/apt-mirrors.txt /etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources; do if [ -f "$source" ]; then sudo sed -i 's|azure.archive.ubuntu.com|archive.ubuntu.com|g; s|http://archive.ubuntu.com|https://archive.ubuntu.com|g' "$source" @@ -513,448 +31,91 @@ jobs: sudo apt-get install --no-install-recommends -y g++-mingw-w64-x86-64 - run: npm run build:windows-native - run: npm run verify:windows-native:artifact - - run: node scripts/build-windows-native.mjs --inspection-fixture - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: windows-native-inspection-fixture - path: .cache/windows-native-inspection-fixture/ - if-no-files-found: error - # The process boundary observations are independent of the addon: they - # report the caller's and child's own token, environment and breakaway - # results from a separate executable. Cross-build it in the lane that - # already has MinGW so the Windows job can observe them too. - - name: Build Windows process boundary fixture - run: | - mkdir -p .cache/windows-process-boundary - x86_64-w64-mingw32-g++ -municode -std=c++17 -O2 -static -Wall -Wextra \ - -o .cache/windows-process-boundary/process-boundary.exe \ - tests/fixtures/windows/processBoundary.cc -ladvapi32 - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: windows-process-boundary-fixture - path: .cache/windows-process-boundary/ - if-no-files-found: error - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: windows-native-controls path: native/windows/build/ if-no-files-found: error - - package-e2e: - name: Native package baseline (${{ matrix.platform }} ${{ matrix.architecture }}) - needs: [changes, static, build, windows-native-build] - if: needs.changes.outputs.runtime == 'true' - strategy: - fail-fast: false - # The four platform jobs use independent hosted runners; keep each - # runner's existing heap and threadpool limits while avoiding a queued - # second platform wave. - max-parallel: 4 - matrix: ${{ fromJSON(needs.changes.outputs.matrix) }} - runs-on: ${{ matrix.os }} - timeout-minutes: 20 - env: - NODE_OPTIONS: "--max-old-space-size=1024" - UV_THREADPOOL_SIZE: "2" - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - name: Verify native runtime identity - env: - EXPECTED_CI_PLATFORM: ${{ matrix.platform }} - EXPECTED_CI_ARCHITECTURE: ${{ matrix.architecture }} - run: >- - node -e "const assert = require('node:assert/strict'); - assert.equal(process.platform, process.env.EXPECTED_CI_PLATFORM); - assert.equal(process.arch, process.env.EXPECTED_CI_ARCHITECTURE); - console.log(JSON.stringify({ platform: process.platform, architecture: process.arch, node: process.version }));" - - run: npm ci - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: rea-build-cache - path: .turbo/cache/ - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: windows-native-controls - path: native/windows/build/ - - run: npm run verify:windows-native:artifact - - name: Verify NativeAOT diagnostic applicability on this host - run: npm run test:focused -- tests/evaluation/package/nativeAotDiagnostics.test.ts - - run: npm run verify:package - env: - npm_config_cache: ${{ steps.npm-cache.outputs.path }} - REA_VERIFIED_PACKAGE_DIRECTORY: ${{ needs.changes.outputs.tier == 'full' && matrix.platform == 'linux' && matrix.architecture == 'x64' && '.cache/verified-package' || '' }} - - name: Verify real Node Inspector discovery and observation - timeout-minutes: 10 - run: npm run verify:inspector - - name: Retain the exact qualified release package - if: needs.changes.outputs.tier == 'full' && matrix.platform == 'linux' && matrix.architecture == 'x64' - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: verified-release-package - path: .cache/verified-package/ - include-hidden-files: true - if-no-files-found: error - overwrite: true retention-days: 7 - - apple-artifacts: - name: Real Apple artifact CLI/MCP E2E - needs: [changes, static, build] - if: needs.changes.outputs.apple == 'true' - runs-on: macos-15 - timeout-minutes: 15 - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - run: npm ci - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: rea-build-cache - path: .turbo/cache/ - - name: Verify Apple artifact formats and metadata - env: - REA_ARTIFACT_NODE_COMPILE_CACHE: ${{ runner.temp }}/rea-artifact-node-cache - run: | - npm run verify:keyed-archive - npm run verify:asset-catalog - npm run verify:macos-bundle - npm run verify:legacy-simulator - npm run verify:apple-dispatch - npm run verify:interface-builder - - name: Run native Apple and process boundary regressions - run: >- - npm run test:focused -- - tests/boundary/filesystem/installScript.test.ts - tests/boundary/filesystem/nibNativeHierarchy.test.ts - tests/boundary/filesystem/interfaceBuilderBundle.test.ts - tests/boundary/cli/nativePlistCli.test.ts - tests/boundary/cli/nativePlistPrototypeKeyCli.test.ts - tests/boundary/cli/nativePlistSelectionFailureCli.test.ts - tests/boundary/cli/nativeDemangleCli.test.ts - tests/boundary/mcp/nativeDemangleMcp.test.ts - tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts - tests/boundary/cli/nativeSignatureCli.test.ts - tests/boundary/mcp/nativeSignatureTargetBindingMcp.test.ts - src/process/capture/FilesystemSnapshot.test.ts - tests/process-global/filesystemSnapshotFallbackCancellation.test.ts - tests/boundary/process/darwinProcessRunTokenReader.test.ts - tests/boundary/process/directAnalysisSignals.test.ts - tests/boundary/process/processCaptureLifecycle.test.ts - tests/boundary/process/processCli.test.ts - tests/boundary/mcp/sessionMcp.test.ts - - reconstruction-readiness: - name: Reconstruction readiness - needs: [changes, static] - if: needs.changes.outputs.readiness == 'true' - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - run: npm ci - - name: Run the public CLI/MCP reconstruction journey - env: - REA_READINESS_REPORT_PATH: readiness-report.json - run: | - set -o pipefail - npm run verify:readiness | tee readiness-summary.json - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - if: ${{ !cancelled() }} - with: - name: reconstruction-readiness - path: | - readiness-summary.json - readiness-report.json - if-no-files-found: error - retention-days: 30 - - windows-curated: - name: Windows capability and package lane - needs: [changes, static, build, windows-native-build] - if: needs.changes.outputs.package == 'true' + windows-proof: + needs: native-build runs-on: windows-latest - timeout-minutes: 25 + timeout-minutes: 20 + defaults: + run: + shell: bash steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + with: + fetch-depth: 0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 with: node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache + - uses: ./.github/actions/npm-cache - run: npm ci - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: rea-build-cache - path: .turbo/cache/ - - run: npm run build:cached - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with: name: windows-native-controls path: native/windows/build/ - run: npm run verify:windows-native:artifact - - name: Record named Windows host capabilities - run: node scripts/windows-capabilities.mjs | Out-File -Encoding utf8NoBOM windows-capabilities.json - - name: Validate Windows host capability report - run: >- - node -e "const report = JSON.parse(require('node:fs').readFileSync('windows-capabilities.json', 'utf8')); - if (report.platform !== 'win32' || report.architecture !== 'x64') - throw new Error('expected a Windows x64 capability report');" - # Keep this list aligned with tests/process-global/curatedWindowsLane.test.ts, - # which fails when any path below is renamed or removed. Vitest silently - # ignores unmatched paths, so a stale entry would otherwise report green - # while skipping coverage. - # - # The matching native artifact establishes real Job Object and private - # runtime boundaries for these fixtures. Ghidra and Java are not needed; - # real engine claims remain in the separate controlled-provider workflow. - - name: Run curated Windows capability tests - run: >- - npx vitest run --coverage.enabled=false - src/process/capture/FilesystemSnapshot.test.ts - tests/process-global/filesystemSnapshotFallbackCancellation.test.ts - tests/boundary/filesystem/binaryTarget.test.ts - tests/boundary/filesystem/safeOutputTree.test.ts - tests/boundary/providers/native/artifactProvider.archiveSafety.test.ts - tests/boundary/providers/native/artifactProvider.extractionCompleteness.test.ts - tests/boundary/filesystem/setupUnavailableProvider.test.ts - tests/boundary/filesystem/windowsNpxRegistration.test.ts - tests/boundary/android/workspaceGuardianRetry.test.ts - tests/acceptance/setup/homeDirectoryFallback.test.ts - tests/boundary/filesystem/javascriptApplicationWorkflows.test.ts - tests/boundary/filesystem/webScriptManifestPaths.test.ts - tests/boundary/process/ProcessEvidence.host.test.ts - tests/boundary/process/packageNpmInvocation.test.ts - tests/boundary/process/windowsOutputCapture.test.ts - tests/acceptance/webModuleCli.test.ts - tests/acceptance/webSourceLocationCli.test.ts - tests/boundary/cli/referenceSourceImportStatus.test.ts - tests/boundary/filesystem/asarInventoryFreshness.test.ts - tests/boundary/filesystem/javascript-applications/javascriptArtifactReconstruction.test.ts - tests/conformance/providers/ghidra/windowsCapabilities.test.ts - src/ghidra/GhidraInstallation.test.ts - tests/boundary/filesystem/ghidraJavaProbe.test.ts - tests/boundary/providers/ghidra/ghidraTransport.test.ts - tests/boundary/providers/ghidra/ghidraTargetSnapshot.test.ts - tests/boundary/providers/ghidra/ghidraLauncher.test.ts - tests/boundary/providers/hopper/hopperClient.cleanupRetry.test.ts - src/windows/WindowsNativeLoader.test.ts - src/windows/WindowsOwnedProcess.test.ts - src/ghidra/GhidraLauncherEnvironment.test.ts - src/process/ProcessOwnership.test.ts - src/process/ProcessOwnership.part2.test.ts - src/process/ProcessOwnership.part3.test.ts - src/process/ProcessOwnership.validation.test.ts - src/application/Update.test.ts - tests/process-global/updateMaintenance.test.ts - tests/conformance/providers/ghidra/realGhidraWindowsWorkflow.test.ts - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: windows-process-boundary-fixture - path: .cache/windows-process-boundary/ - # Passing the fixture adds the breakaway, caller/child token, environment - # semantics and ancestor reparse observations, which the lane skips - # entirely when it is absent. - - run: >- - npm run verify:windows-native -- . - "${{ github.workspace }}\.cache\windows-process-boundary\process-boundary.exe" - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: windows-native-inspection-fixture - path: .cache/windows-native-inspection-fixture/ - - name: Verify native inspection failure ownership and recovery - run: node scripts/verify-windows-native-inspection.mjs - - name: Verify real Node Inspector discovery and observation - timeout-minutes: 10 - env: - NODE_OPTIONS: "--max-old-space-size=1024" - UV_THREADPOOL_SIZE: "2" - run: npm run verify:inspector - - run: npm run verify:package:windows - - name: Verify native directory identity on Node 24 - run: >- - npx vitest run --coverage.enabled=false - tests/boundary/filesystem/directoryArtifactReaderOpen.test.ts - tests/boundary/filesystem/javascriptPackagePrecedence.test.ts - tests/boundary/filesystem/javascriptArtifactContentIdentity.test.ts - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: 22.19.0 - - name: Verify native path boundaries on Node 22 - run: >- - npx vitest run --coverage.enabled=false - tests/boundary/filesystem/directoryArtifactReaderOpen.test.ts - tests/boundary/filesystem/javascriptPackagePrecedence.test.ts - tests/boundary/filesystem/javascriptArtifactContentIdentity.test.ts - tests/boundary/process/sourceMapUncHosts.test.ts - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + - run: npm run build:cached + - name: Observe actual baseline failure and corrected public CLI workflows + run: | + node --input-type=module - <<'JS' + import assert from "node:assert/strict"; + import { readFileSync, writeFileSync, mkdirSync, rmSync } from "node:fs"; + import { execFileSync, spawnSync } from "node:child_process"; + import { resolve } from "node:path"; + assert.equal(process.platform, "win32"); + const source = process.env.PROOF_SOURCE; + const base = process.env.PROOF_BASE; + assert.equal(execFileSync("git", ["diff", "--name-only", source, "HEAD"], { encoding: "utf8" }).trim(), ".github/workflows/ci.yml"); + execFileSync("git", ["diff", "--exit-code", "HEAD", "--"]); + const path = "tests/acceptance/applications/applicationWorkflowCli.test.ts"; + const candidate = readFileSync(path, "utf8"); + const baseline = execFileSync("git", ["show", `${base}:${path}`], { encoding: "utf8" }); + const targets = "compares captured primitives and source values after aliases are replaced"; + mkdirSync(".cache/windows-proof", { recursive: true }); + const run = (name, pattern) => { + const output = `.cache/windows-proof/${name}.json`; + rmSync(output, { force: true }); + const started = performance.now(); + const child = spawnSync(process.execPath, [resolve("node_modules/vitest/vitest.mjs"), "run", "--project=acceptance", path, "--maxWorkers=1", "--coverage.enabled=false", `--testNamePattern=${pattern}`, "--reporter=json", `--outputFile=${output}`], { encoding: "utf8", maxBuffer: 8 * 1024 * 1024 }); + if (child.error) throw child.error; + const log = `${child.stdout}\n${child.stderr}`; + writeFileSync(`.cache/windows-proof/${name}.log`, log); + const report = JSON.parse(readFileSync(output, "utf8")); + return { exit: child.status, elapsed_ms: performance.now() - started, report, log }; + }; + let failed; + try { + writeFileSync(path, baseline); + failed = run("baseline", targets); + assert.equal(failed.exit, 1); + assert.equal(failed.report.numFailedTests, 1); + assert.equal(failed.report.numPassedTests, 0); + const failures = failed.report.testResults.flatMap((suite) => suite.assertionResults).filter((test) => test.status === "failed"); + assert.equal(failures.length, 1); + for (const test of failures) assert.match(test.failureMessages.join("\n"), /ERR_UNSUPPORTED_ESM_URL_SCHEME/); + } finally { + writeFileSync(path, candidate); + } + const fixed = run("candidate", ".*"); + assert.equal(fixed.exit, 0); + assert.equal(fixed.report.numPassedTests, 34); + assert.equal(fixed.report.numFailedTests, 0); + assert.equal(fixed.report.numPendingTests, 0); + assert.equal(fixed.report.testResults.length, 1); + execFileSync("git", ["diff", "--exit-code", "HEAD", "--"]); + const receipt = { source, base, platform: process.platform, architecture: process.arch, node: process.version, baseline_failed: failed.report.numFailedTests, baseline_import_error: "ERR_UNSUPPORTED_ESM_URL_SCHEME", baseline_elapsed_ms: failed.elapsed_ms, candidate_passed: fixed.report.numPassedTests, candidate_elapsed_ms: fixed.elapsed_ms, selected_skips: fixed.report.numPendingTests, instrumentation: "Unmodified baseline source; original ESM loader error verified in structured failure messages. Candidate source restored and checked before completion." }; + writeFileSync(".cache/windows-proof/receipt.json", JSON.stringify(receipt, null, 2)); + console.log(JSON.stringify(receipt)); + JS + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 if: always() with: - name: windows-capabilities - path: windows-capabilities.json - retention-days: 30 - - docs: - name: Docs Generation - needs: changes - if: needs.changes.outputs.docs == 'true' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Cache npm package downloads - id: npm-cache - uses: ./.github/actions/npm-cache - - run: npm ci - - run: npm run docs:check - - name: Generation leaves authored files unchanged - run: git diff --exit-code - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: generated-docs - path: | - docs/public/product-catalog.json - docs/verification/managed-conformance-*.json - skills/reverse-engineer-anything + name: native-windows-fixture-proof + path: .cache/windows-proof/ + include-hidden-files: true if-no-files-found: error - - browser: - needs: [changes, static, build] - if: needs.changes.outputs.browser == 'true' - uses: ./.github/workflows/real-browser.yml - with: - build_cache_artifact: rea-build-cache - - binary_layout: - needs: [changes, static, build] - if: needs.changes.outputs.binary_layout == 'true' - uses: ./.github/workflows/real-binary-layout.yml - with: - build_cache_artifact: rea-build-cache - - evm: - needs: [changes, static, build] - if: needs.changes.outputs.evm == 'true' - uses: ./.github/workflows/real-evm-interface.yml - with: - build_cache_artifact: rea-build-cache - - javascript_recovery: - needs: [changes, static, build] - if: needs.changes.outputs.javascript_recovery == 'true' - uses: ./.github/workflows/real-javascript-recovery.yml - with: - build_cache_artifact: rea-build-cache - - recorded_crash: - needs: [changes, static, build] - if: needs.changes.outputs.recorded_crash == 'true' - uses: ./.github/workflows/real-recorded-crash.yml - with: - build_cache_artifact: rea-build-cache - - web_network: - needs: [changes, static, build] - if: needs.changes.outputs.web_network == 'true' - uses: ./.github/workflows/real-web-network-captures.yml - with: - build_cache_artifact: rea-build-cache - - web_runtime: - needs: [changes, static, build] - if: needs.changes.outputs.web_runtime == 'true' - uses: ./.github/workflows/real-web-runtime.yml - with: - build_cache_artifact: rea-build-cache - - web_source_map: - needs: [changes, static, build] - if: needs.changes.outputs.web_source_map == 'true' - uses: ./.github/workflows/real-web-source-map.yml - with: - build_cache_artifact: rea-build-cache - - nativeaot: - needs: [changes, static] - if: needs.changes.outputs.nativeaot == 'true' - uses: ./.github/workflows/nativeaot-fixtures.yml - - website: - needs: [changes, static] - if: needs.changes.outputs.website == 'true' - uses: ./.github/workflows/website-check.yml - - required: - name: CI required - # Report failed dependencies, but release superseded PR concurrency slots. - if: ${{ !cancelled() }} - needs: - [ - changes, - static, - build, - reverse-tools-quality, - test-shard, - test-source, - sqlite-runtime, - test, - conformance-fixtures, - windows-native-build, - package-e2e, - apple-artifacts, - reconstruction-readiness, - windows-curated, - docs, - browser, - binary_layout, - evm, - javascript_recovery, - recorded_crash, - web_network, - web_runtime, - web_source_map, - nativeaot, - website, - ] - runs-on: ubuntu-24.04 - timeout-minutes: 5 - steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - name: Require every selected lane to pass - id: gate - env: - CI_JOBS: ${{ toJSON(needs) }} - CI_QUALIFICATION_DIRECTORY: .cache/ci-qualification - run: node scripts/ci/required.mjs - - name: Upload full qualification receipt artifact - if: needs.changes.outputs.tier == 'full' && success() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: ${{ steps.gate.outputs.receipt_name }} - path: ${{ steps.gate.outputs.receipt_path }} - if-no-files-found: error - overwrite: true retention-days: 7