name: Check # Two jobs. `gate` (Linux, a few cents) runs on every PR and push: architecture, typecheck, lint # test style, baseline contracts, affected behavior tests and, when a change reaches it, the # harness gate (npm run verify:harness). `fast` (macOS) runs non-rig tests, # only where paid runners belong: PRs into main (dev -> main is opened by hand), pushes to main # and manual runs. A skipped job bills nothing. The rig suites run from rig.yml. This workflow # never listens to label events, so a label can never replace a code-event run with a skipped one. # No secrets; pull_request runs with the fork's read-only token. on: pull_request: types: [opened, synchronize, reopened] push: branches: [dev, main] workflow_dispatch: permissions: contents: read concurrency: group: check-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: gate: runs-on: ubuntu-22.04 timeout-minutes: 30 steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: persist-credentials: false # origin/dev lets check-test-style refuse allowlist additions against the merge base. fetch-depth: 0 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: npm # Fast behavior tests use synthetic runtimes; no Electron download or native rebuild. - name: Linux process sandbox prerequisites run: sudo apt-get update && sudo apt-get install -y bubblewrap socat ripgrep - run: npm ci --ignore-scripts # --ignore-scripts skips postinstall, which patches sandbox-runtime's executable lookup. - name: Patch the sandbox runtime as postinstall does run: node --input-type=module -e "await (await import('./scripts/patch-sandbox-runtime.mjs')).patchSandboxRuntime()" - run: npm run verify:architecture - run: npm run typecheck - run: npm run lint - run: node scripts/check-test-style.ts # Public cases only; `--with-holdouts` is for the owner's machine and never runs in CI. - name: Eval case isolation run: node scripts/evals/check-isolation.ts - name: Baseline behavior contracts run: node scripts/test.mjs tests/conformance/seed-upgrade.test.ts tests/conformance/child-env.test.ts tests/conformance/words.test.ts tests/conformance/check-grammar.test.ts - name: Change base env: STUDIO_TEST_BASE: ${{ github.event.pull_request.base.sha || github.event.before }} run: | if [ -z "$STUDIO_TEST_BASE" ] || ! git cat-file -e "$STUDIO_TEST_BASE^{commit}" 2>/dev/null; then if git rev-parse --verify HEAD^ >/dev/null 2>&1; then STUDIO_TEST_BASE=$(git rev-parse HEAD^) else STUDIO_TEST_BASE=$(git hash-object -t tree /dev/null) fi fi echo "STUDIO_TEST_BASE=$STUDIO_TEST_BASE" >> "$GITHUB_ENV" - name: Affected behavior tests run: node scripts/affected-tests.mjs --tier L1 --run --base "$STUDIO_TEST_BASE" # The harness's own behavior (harness-incidents and the scoreboard) before a loop or seed # change merges. They boot the rig, so the selector files them under L3; run them here only # when the change reaches them. - name: Harness behavior gate run: | if node scripts/affected-tests.mjs --tier L3 --json --base "$STUDIO_TEST_BASE" | node scripts/harness-gate-selected.mjs; then npm run verify:harness else echo "No change reaches the harness gate." fi fast: if: github.event_name == 'workflow_dispatch' || github.base_ref == 'main' || github.ref == 'refs/heads/main' runs-on: macos-26 timeout-minutes: 30 steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: persist-credentials: false # origin/dev lets check-test-style refuse allowlist additions against the merge base. fetch-depth: 0 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: npm - run: npm ci - run: npm run verify:architecture - run: npm run typecheck - run: npm run lint - run: node scripts/check-test-style.ts - run: node scripts/test.mjs --group fast