You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A deep CI audit (2026-08-29, line-cited evidence in the PRs that will reference this issue) found gates that are broken or silently not running. Part of #1582's hardening goal; this is the repair layer, and it lands first in the CI track — everything here is toolchain-neutral and must not wait for the Node/pnpm migration (#1596–#1598).
Confirmed broken:
ci-server-clean-reference.yml:80 pins a 39-character SHA (actions/upload-artifact@043fb46d…fc6a0 — the valid pin elsewhere ends …fc6a0a) — unresolvable, so the weekly server phase-reference workflow has been dead since perf(server): reuse generated client build outputs #1529.
openapi-autocommit.yml:28 passes cache-type: openapi-validation, which setup-caches does not recognise; every step in the composite is if:-gated on known types, so the composite succeeds while doing nothing — the job runs Maven with no pinned JDK and no cache.
13 of 21 scripts/*.test.ts files never run in CI (only 8 are reachable, via check:changesets, check:preview-stack, check:env, check:contracts, check:instructions, check:java-nullness): ci:agents drops the test:tooling leg that check:agents runs. The release supply-chain suites (check-release-sbom, check-release-vulnerabilities, release-image-lock, release-deployment-policy) and the preview-controller suites are local-only. check:agent-runtime-pins and check-release-image-inventory.ts also appear in no workflow.
20 runnable jobs have no timeout-minutes (default 360 min), including both reusable-docker-build jobs, deploy-locked-compose/deploy, and the four release.yml jobs that can carry the key (release, tag-images, publish-release, deploy-production — deploy-staging is a reusable-workflow caller, where the key is invalid; caller jobs get their bounds inside the called workflows' jobs instead).
concurrency.queue: max (preview lifecycle: deploy-preview.yml:36, cleanup-preview.yml:13, reconcile-previews.yml:69) is not a documented GitHub key, and .github/actionlint.yaml exists solely to suppress the resulting error. If GitHub ignores it, the group falls back to "one pending run, newer cancels older" — queued preview teardowns get dropped, the exact opposite of the in-file comment's intent.
Migration consistency: write scripts/ci-contract.test.ts in node:test style so the #1597 runtime port is a no-op. The interim wiring of test:tooling into CI may touch npm scripts that #1595 later reshapes into the vp task graph — #1595 re-points the contract test's "every gate referenced by CI" assertion at the graph; the assertions themselves are designed to survive that.
Done when
The 39-char SHA is fixed and the weekly workflow runs again
setup-cachesfails closed on an unknown cache-type (explicit validation step, not if:-gating) and openapi-autocommit passes a recognised one
test:tooling, check:agent-runtime-pins, and the release-inventory check run in CI (fold ci:agents into check:agents with an env-driven -f github flag)
Every job that can carry timeout-minutes has one; reusable-workflow callers are bounded inside the called workflow
queue: max is empirically verified against a real burst or replaced with documented semantics — and the actionlint suppression in .github/actionlint.yaml is removed either way
Both server test legs pass -Dspring-boot.repackage.skip=true
A new scripts/ci-contract.test.ts (node:test) asserts: every leg of package.json#check is referenced by ≥1 workflow; every cache-type passed in workflows is recognised by setup-caches; every external uses: matches @[0-9a-f]{40} # v — so this whole class of drift cannot recur
Non-deferrable core
Deferral protocol (epic #1608): removing any item below from the implementing PR requires a linked follow-up issue filed before merge, naming the concrete blocker. Silent scope-shedding fails review.
The ci-contract.test.ts with all three assertions (check-leg wiring, cache-type recognition, SHA-pin format) — it is the point of the issue
Fail-closed setup-caches and timeouts on every capable job
-Dspring-boot.repackage.skip=true on both server test legs
queue: max may resolve either way, but it must be resolved, not deferred — the actionlint suppression falls either way
A deep CI audit (2026-08-29, line-cited evidence in the PRs that will reference this issue) found gates that are broken or silently not running. Part of #1582's hardening goal; this is the repair layer, and it lands first in the CI track — everything here is toolchain-neutral and must not wait for the Node/pnpm migration (#1596–#1598).
Confirmed broken:
ci-server-clean-reference.yml:80pins a 39-character SHA (actions/upload-artifact@043fb46d…fc6a0— the valid pin elsewhere ends…fc6a0a) — unresolvable, so the weekly server phase-reference workflow has been dead since perf(server): reuse generated client build outputs #1529.openapi-autocommit.yml:28passescache-type: openapi-validation, whichsetup-cachesdoes not recognise; every step in the composite isif:-gated on known types, so the composite succeeds while doing nothing — the job runs Maven with no pinned JDK and no cache.scripts/*.test.tsfiles never run in CI (only 8 are reachable, viacheck:changesets,check:preview-stack,check:env,check:contracts,check:instructions,check:java-nullness):ci:agentsdrops thetest:toolingleg thatcheck:agentsruns. The release supply-chain suites (check-release-sbom,check-release-vulnerabilities,release-image-lock,release-deployment-policy) and the preview-controller suites are local-only.check:agent-runtime-pinsandcheck-release-image-inventory.tsalso appear in no workflow.timeout-minutes(default 360 min), including bothreusable-docker-buildjobs,deploy-locked-compose/deploy, and the fourrelease.ymljobs that can carry the key (release,tag-images,publish-release,deploy-production—deploy-stagingis a reusable-workflow caller, where the key is invalid; caller jobs get their bounds inside the called workflows' jobs instead).concurrency.queue: max(preview lifecycle:deploy-preview.yml:36,cleanup-preview.yml:13,reconcile-previews.yml:69) is not a documented GitHub key, and.github/actionlint.yamlexists solely to suppress the resulting error. If GitHub ignores it, the group falls back to "one pending run, newer cancels older" — queued preview teardowns get dropped, the exact opposite of the in-file comment's intent.test:server:*scripts run thepackagephase (since fix(ci): package reactor dependencies before server tests #1585), so both server test legs repackage the Spring Boot fat JAR for nothing — add-Dspring-boot.repackage.skip=true. (perf(ci): cut PR feedback time from ~12 to ~6 minutes #1590 measures the effect; this issue owns the fix.)Migration consistency: write
scripts/ci-contract.test.tsinnode:teststyle so the #1597 runtime port is a no-op. The interim wiring oftest:toolinginto CI may touch npm scripts that #1595 later reshapes into the vp task graph — #1595 re-points the contract test's "every gate referenced by CI" assertion at the graph; the assertions themselves are designed to survive that.Done when
setup-cachesfails closed on an unknowncache-type(explicit validation step, notif:-gating) andopenapi-autocommitpasses a recognised onetest:tooling,check:agent-runtime-pins, and the release-inventory check run in CI (foldci:agentsintocheck:agentswith an env-driven-f githubflag)timeout-minuteshas one; reusable-workflow callers are bounded inside the called workflowqueue: maxis empirically verified against a real burst or replaced with documented semantics — and the actionlint suppression in.github/actionlint.yamlis removed either way-Dspring-boot.repackage.skip=truescripts/ci-contract.test.ts(node:test) asserts: every leg ofpackage.json#checkis referenced by ≥1 workflow; everycache-typepassed in workflows is recognised bysetup-caches; every externaluses:matches@[0-9a-f]{40} # v— so this whole class of drift cannot recurNon-deferrable core
Deferral protocol (epic #1608): removing any item below from the implementing PR requires a linked follow-up issue filed before merge, naming the concrete blocker. Silent scope-shedding fails review.
ci-contract.test.tswith all three assertions (check-leg wiring, cache-type recognition, SHA-pin format) — it is the point of the issuesetup-cachesand timeouts on every capable job-Dspring-boot.repackage.skip=trueon both server test legsqueue: maxmay resolve either way, but it must be resolved, not deferred — the actionlint suppression falls either way