5353 name : Swift Runner Unit Compile
5454 runs-on : macos-26
5555 timeout-minutes : 20
56+ # Was an inline `VAR=1 pnpm gate …` prefix on the action's build-command input. The
57+ # input is a gate id now, so the variable lives where ios.yml already puts it: the job.
58+ env :
59+ AGENT_DEVICE_XCUITEST_INCLUDE_UNIT_TESTS : ' 1'
5660 steps :
5761 - name : Checkout
5862 uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6569 with :
6670 derived-path : ${{ github.workspace }}/.tmp/swift-runner-unit-derived
6771 cache-key-prefix : swift-runner-unit
68- build-command : AGENT_DEVICE_XCUITEST_INCLUDE_UNIT_TESTS=1 pnpm build:xcuitest: macos
72+ gate : swift-runner- macos
6973 xcuitest-platform : macos
7074 xcuitest-destination : platform=macOS,arch=arm64
7175
@@ -81,10 +85,10 @@ jobs:
8185 uses : ./.github/actions/setup-node-pnpm
8286
8387 - name : Run oxlint
84- run : pnpm lint
88+ run : pnpm gate lint
8589
8690 - name : Check formatting
87- run : pnpm format:check
91+ run : pnpm gate format
8892
8993 layering-guard :
9094 name : Layering Guard
@@ -107,14 +111,28 @@ jobs:
107111 # Generalizes the former inline commands/-import grep into a structured
108112 # import-direction lint over the resolved graph. See scripts/layering/check.ts
109113 # and CONTEXT.md (Architecture: folder DAG + layering lint).
110- run : pnpm check: layering
114+ run : pnpm gate layering
111115
112116 - name : Check the depgraph report agrees with the gate
113117 # scripts/depgraph reads the same model as the gate, so its inversion count must
114118 # reproduce TYPE_INVERSION_BASELINE. Free two-sources check: if the tree changes
115119 # and only one side is updated, this fails and names the difference. Runs here
116120 # rather than in its own job so the two can never be green independently.
117- run : pnpm depgraph:test
121+ run : pnpm gate depgraph
122+
123+ # The TMPDIR redirection both test lanes rely on (#1593/#1595). Its own tests ran
124+ # in no CI job at all until the #1429 gate manifest found them unowned.
125+ #
126+ # Deliberately NOT in the Coverage job next to `check:tmpdir-leaks`, where the
127+ # subject matter would put it: vitest-tmpdir-global-setup.test.ts proves the
128+ # lifecycle by spawning a real nested `vitest run`, and the Coverage lane already
129+ # loses runs to `[vitest-pool]: Worker forks emitted error` when a fork is slow to
130+ # terminate (observed on main at 18291ba8, unrelated to this gate). Starting a
131+ # nested Vitest seconds before the full instrumented suite is a contention risk
132+ # with nothing to gain — the manifest proves ownership per unit of work, so any
133+ # lane satisfies it.
134+ - name : Check the tmpdir redirection model
135+ run : pnpm gate tmpdir-leaks-model
118136
119137 # Tests for the TMPDIR redirection itself, hidden the same way as the check above.
120138 #
@@ -146,7 +164,18 @@ jobs:
146164 # The selector is fail-open and advisory (GitHub CI stays authoritative),
147165 # so the gate only guards the derivation model.
148166 - name : Check affected-selector model
149- run : pnpm check:affected:test
167+ run : pnpm gate affected-selector
168+
169+ # The gate-of-gates (#1429). It shares this job because it validates the
170+ # same artifact the selector is built on — CHECK_CATALOG's `ciJobs` — and
171+ # because a gate that proves the other gates are wired must not be the one
172+ # gate sitting in its own job, green on its own. Deterministic and
173+ # network-free: every input is a file in the checkout.
174+ - name : Check the gate manifest model
175+ run : pnpm gate gate-manifest-model
176+
177+ - name : Check every gate is owned, wired, and reachable
178+ run : pnpm gate gate-manifest
150179
151180 maestro-conformance :
152181 name : Maestro Conformance Oracle
@@ -168,7 +197,7 @@ jobs:
168197 # device-backed layer 3 runs on the scheduled conformance-differential
169198 # workflow. See scripts/maestro-conformance/README.md.
170199 - name : Verify Maestro conformance fixtures
171- run : pnpm maestro: conformance
200+ run : pnpm gate maestro- conformance
172201
173202 packaged-cli-node-22-12 :
174203 name : Packaged CLI Node 22.12
@@ -183,8 +212,8 @@ jobs:
183212
184213 - name : Build CLI
185214 run : |
186- pnpm build
187- pnpm check: bundle-owner-files
215+ pnpm gate build
216+ pnpm gate bundle-owner-files
188217
189218 # The build runs on the default toolchain Node and the package is verified on the minimum
190219 # supported Node, so this job covers what a user on `engines.node` floor actually installs.
@@ -218,10 +247,10 @@ jobs:
218247 - name : Run Fallow audit
219248 env :
220249 FALLOW_BASE : ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
221- run : pnpm check: fallow --base "$FALLOW_BASE"
250+ run : pnpm gate fallow --base "$FALLOW_BASE"
222251
223252 - name : Check for production-unused exports
224- run : pnpm check: production-exports
253+ run : pnpm gate production-exports
225254
226255 replay-compat-provenance :
227256 # The frozen replay-compat corpus (#1417) claims each entry was published by
@@ -241,7 +270,7 @@ jobs:
241270 uses : ./.github/actions/setup-node-pnpm
242271
243272 - name : Verify corpus entries against their released blobs
244- run : pnpm check: replay-compat
273+ run : pnpm gate replay-compat
245274
246275 released-surface-compat :
247276 # The daemon RPC wire ledger (#1432) is compared against the ledger as it
@@ -262,10 +291,10 @@ jobs:
262291 uses : ./.github/actions/setup-node-pnpm
263292
264293 - name : Verify the wire-compat rules
265- run : pnpm check:daemon- wire-compat:test
294+ run : pnpm gate wire-compat-model
266295
267296 - name : Compare the daemon RPC wire surface against the last released tag
268- run : pnpm check: daemon-wire-compat
297+ run : pnpm gate daemon-wire-compat
269298
270299 coverage :
271300 # Runs the full unit + provider-integration suites under coverage with
@@ -283,20 +312,29 @@ jobs:
283312 uses : ./.github/actions/setup-node-pnpm
284313
285314 - name : Test changed-line coverage gate
286- run : pnpm check: coverage-changed:test
315+ run : pnpm gate coverage-model
287316
288317 # The retry list is an enumerated set of owned waivers, so an expired entry
289318 # must fail before the suite runs rather than quietly keeping its retry.
290319 - name : Check contention retry policy
291- run : pnpm check: contention-retry
320+ run : pnpm gate contention-retry
292321
293322 # Wrapped in the single-retry policy (#1419): a timeout-shaped failure in
294323 # an enumerated contention-flaky file reruns that file once and reports it
295324 # in the job summary. Assertion failures fail here on the first run.
296325 - name : Run coverage
297326 env :
298327 OUTPUT_ECONOMY_BASE : ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
299- run : pnpm test:coverage:ci
328+ run : pnpm gate unit-ci
329+
330+ # A run whose globalTeardown never fired (crash, OOM, timeout kill) leaves
331+ # its tmpdir behind. `check:unit` runs this locally after the suite; until
332+ # #1429 nothing ran it in CI, which is the environment where those kills
333+ # actually happen. Runs even on failure — a killed run is exactly the case
334+ # worth reporting.
335+ - name : Check for leaked test tmpdirs
336+ if : always()
337+ run : pnpm gate tmpdir-leaks
300338
301339 # The TMPDIR redirection both test lanes depend on (#1593/#1595). The check is a real
302340 # package script that no workflow ran: it is reachable only through `check:unit`, an
@@ -321,7 +359,7 @@ jobs:
321359 if : always() && github.event_name == 'pull_request'
322360 env :
323361 AGENT_DEVICE_COVERAGE_WAIVER : ${{ contains(github.event.pull_request.labels.*.name, 'coverage-waiver') }}
324- run : pnpm check: coverage-changed --base "${{ github.event.pull_request.base.sha }}"
362+ run : pnpm gate coverage --base "${{ github.event.pull_request.base.sha }}"
325363
326364 typecheck :
327365 name : Typecheck
@@ -335,7 +373,14 @@ jobs:
335373 uses : ./.github/actions/setup-node-pnpm
336374
337375 - name : Run typecheck
338- run : pnpm typecheck
376+ run : pnpm gate typecheck
377+
378+ # CHECK_CATALOG has always claimed this job mirrors the `mcp-metadata`
379+ # check; until #1429 checked the claim, no PR job ran it at all, so
380+ # server.json/smithery.yaml drift only surfaced at publish time (where
381+ # publish-mcp-registry.yml duplicates the same command). Parse-only.
382+ - name : Check MCP registry metadata is in sync
383+ run : pnpm gate mcp-metadata
339384
340385 freerange :
341386 name : FreeRange
@@ -352,7 +397,7 @@ jobs:
352397 uses : oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
353398
354399 - name : Check numeric ranges
355- run : pnpm check: freerange
400+ run : pnpm gate freerange
356401
357402 integration :
358403 name : Integration Tests
@@ -368,27 +413,33 @@ jobs:
368413 - name : Run integration tests
369414 run : |
370415 pnpm clean:daemon
371- pnpm test: integration: node
416+ pnpm gate integration- node
372417
373418 - name : Run seeded concurrency torture lane (fast PR sweep)
374419 # #1416's nightly torture lane lives under test/integration/nightly/, out
375420 # of the test:integration:node glob, so this is a *deliberate* fast PR
376421 # sweep (TORTURE_RUNS default 128 seeds, ~sub-second) — not an accidental
377422 # glob inclusion. The Concurrency Torture Nightly workflow sweeps a much
378423 # larger seed range on schedule.
379- run : pnpm test: concurrency-torture
424+ run : pnpm gate concurrency-torture
380425
381426 - name : Run provider-backed integration tests
382- run : pnpm test:integration: provider
427+ run : pnpm gate provider-integration
383428
384429 - name : Check Provider-backed integration architecture progress
385- run : pnpm test: integration: progress:check
430+ run : pnpm gate integration- progress
386431
387432 # A build-cache lookup outage must degrade setup-fixture-app to an inline
388433 # build, not fail the caller. This drives that step's real shell against a
389434 # failing `gh`.
390435 - name : Setup-fixture-app cache-failure fallback
391- run : sh ./test/scripts/setup-fixture-app-fallback-smoke.sh
436+ run : pnpm gate fixture-fallback
437+
438+ # The trust rules that decide whether a cached fixture APK/app may be
439+ # reused at all — same subject as the fallback smoke above, and parse-only.
440+ # Ran in no CI job until the #1429 gate manifest found it unowned.
441+ - name : Check trusted fixture-artifact selection
442+ run : pnpm gate fixture-cache
392443
393444 # The trusted-artifact contract the device lanes rely on to decide a cached fixture
394445 # app is the one this commit expects. A real test file that no workflow ran.
@@ -413,7 +464,7 @@ jobs:
413464 - name : Run live web smoke
414465 run : |
415466 pnpm clean:daemon
416- pnpm test:smoke: web
467+ pnpm gate web-smoke
417468
418469 - name : Upload web smoke artifacts
419470 if : always()
0 commit comments