Fix: Required CI gate fails when the lifecycle gate fails (#796) - #797
Merged
Merged
Conversation
`Required CI gate` passes when `implementation-gate` ("SpecSync
implementation ready") passes. That job needed neither `preflight` nor
`lifecycle-gate`, and it accepted `success` or `skipped` from every job
it did need. When the lifecycle gate failed, `test`, `audit`, `coverage`
and `spec-check` were skipped rather than failed, and both gates went
green. #795 showed it at bb1d80f.
`implementation-gate` now needs every job that can finish before it,
`preflight` and `lifecycle-gate` included. Its step reads one row per
job: the job's own `if:` (less a leading `always() &&`), evaluated again
over the same classify outputs, and the job's result. `skipped` passes
only where that says classify deselected the job. A selected job that
was skipped had a dependency that did not succeed, and it fails the
gate. The old check that nothing in `needs` failed or was cancelled
stays, and the gate fails if its rows do not cover `needs`.
`.github/scripts/test-required-ci-gate.py` guards it. It fails if
`preflight` or `lifecycle-gate` leaves `implementation-gate.needs`, if a
job that gates on `lifecycle-gate` or otherwise runs before the gate is
missing, or if a row drifts from its job's `if:`. It simulates the job
graph for every classify lane and flag combination under
pull_request, push and workflow_dispatch, runs the gate's own bash, and
requires the required gate to be green when every selected job succeeds
and red when any one fails or is cancelled. The pre-#796 gate,
kept as a fixture, reproduces the bug in the same simulation. It runs
in `validate-action` and as the Fledge task `ci-gate-test` in the
verify, ci and repo lanes.
SpecSync change: required-ci-gate-fails-when-the-lifecycle-gate-fails
(draft; definition approval is left to the owner).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3ZZAEiUP7xRJPozhZb6rL
0xLeif
requested review from
0xGaspar,
Kyntrin and
tofu-ux
and removed request for
a team
September 26, 2026 15:33
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
The CI log for the first push shows the gate's step running as
`/usr/bin/bash -e {0}`: a step that names no shell gets `bash -e`, not
the `bash --noprofile --norc -eo pipefail` that `shell: bash` gets. The
simulation now uses the same invocation for each case. Results are
unchanged.
Record the live check in the change's testing notes: on the unapproved
draft `Lifecycle gate` failed, `test`, `audit`, `coverage` and
`spec-check` were skipped, and `SpecSync implementation ready` and
`Required CI gate` both failed, with one annotation per cause.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3ZZAEiUP7xRJPozhZb6rL
This was referenced Sep 26, 2026
…te-fails verification
There was a problem hiding this comment.
✅ Corvin says...
_
<(^\ .oO(Caw! ^v^)
|/(\
\(\\
" "\\
"That's a nice looking export you've got there."
CI Summary
| Check | Status |
|---|---|
| Validate action.yml | ✅ Passed |
| Packaged Action Consumer | ✅ Passed |
| Dependency Audit | ✅ Passed |
| Code Coverage | ✅ Passed |
| Format Check | ✅ Passed |
| Human intent check | ✅ Passed |
| Docs Site | ✅ Passed |
| Spec Validation | ✅ Passed |
| Tests (build, test, clippy) | ✅ Passed |
| VS Code Extension | ✅ Passed |
📋 Spec Validation Details
✅ SpecSync: Passed
| Metric | Value |
|---|---|
| Specs checked | 62 |
| Passed | 62 |
| Errors | 0 |
| Warnings | 0 |
| File coverage | 100% (107/107) |
| LOC coverage | 100% (149230/149230) |
Generated by specsync · Run specsync check --format github to reproduce
Powered by corvid-pet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #796.
Summary
Required CI gatepasses whenSpecSync implementation ready(implementation-gate) passes. That job needed neitherpreflightnorlifecycle-gate, and it acceptedsuccessorskippedfrom every job it did need. When the lifecycle gate failed,test,audit,coverageandspec-checkwere skipped rather than failed, and both gates went green. Fix: lifecycle commits stage only what the change owns, never git add -A #795 showed it atbb1d80f2..github/workflows/ci.yml).implementation-gatenow needs every job that can finish before it,preflightandlifecycle-gateincluded. Its step reads oneGATESrow per job,<job> <selected> <result>, where<selected>is that job's ownif:(less a leadingalways() &&), evaluated again over the same classify outputs.skippedpasses only where that says classify deselected the job. A selected job that was skipped had a dependency that did not succeed, and it fails the gate. The old "nothing inneedsfailed or was cancelled" check stays, and the gate also fails if its rows do not coverneeds.ci-gateis unchanged..github/scripts/test-required-ci-gate.py, 29 tests). It parsesci.ymlwith Psych, like the other workflow validators, and fails ifpreflightorlifecycle-gateleavesimplementation-gate.needs, if a job that gates onlifecycle-gateor otherwise runs before the gate is missing, or if a row's selection drifts from its job'sif:. It then simulates the job graph (with GitHub's implicit, transitivesuccess()) for every classify lane and runs the gate's own bash underbash -e, which is how the runner invokes a step that names no shell. The pre-CI: Required CI gate passes when the lifecycle gate fails (skipped jobs read as green) #796 gate, kept as a fixture, reproduces the bug in the same harness. It runs invalidate-actionand as the Fledge taskci-gate-testin theverify,ciandrepolanes.docs/HLD.mdsays what the implementation gate requires. Thegithubdelta adds the invariant andREQ-github-021; thegithubcompanions record the decision and the tests.required-ci-gate-fails-when-the-lifecycle-gate-fails: a draft, waiting on Leif's definition approval.This pull request proves the fix
The change is not approved yet, so
Lifecycle gatefails on this head. Before this fix that leftRequired CI gategreen, as on #795 atbb1d80f2. On this PR's first head17e63f5d(run 36252382792),Lifecycle gatefailed,test,audit,coverageandspec-checkwere skipped exactly as on #795, and this timeSpecSync implementation readyandRequired CI gateboth failed, with one annotation per cause:They stay red until the change is approved and
change check --commitlands.Gate rule
truesuccessfalseskippedtrueskippedtruefailure/cancelledfalseskippedif:Truth table
Generated by
python3 .github/scripts/test-required-ci-gate.py --truth-table.classify,preflightandlifecycle-gateare selected on every path. "Required CI gate" verdicts:classify,preflight,lifecycle-gateskippedpasseslifecycle-gatefailspreflightfailslifecycle-gatefails, before this fixpull_requesttest,fmt,hi-check,audit,coverage,site,vscode-extension,validate-action,action-consumer,spec-checkcorvid-petpull_requesttest,fmt,hi-check,audit,coverage,site,vscode-extension,validate-action,action-consumer,spec-check,corvid-petpull_requestsite,validate-action,spec-checktest,fmt,hi-check,audit,coverage,vscode-extension,action-consumer,corvid-petpull_requestvscode-extension,validate-action,spec-checktest,fmt,hi-check,audit,coverage,site,action-consumer,corvid-petpull_requestsite,vscode-extension,validate-action,spec-checktest,fmt,hi-check,audit,coverage,action-consumer,corvid-petpull_requestvalidate-action,spec-checktest,fmt,hi-check,audit,coverage,site,vscode-extension,action-consumer,corvid-petpull_requestvalidate-action,spec-check,corvid-pettest,fmt,hi-check,audit,coverage,site,vscode-extension,action-consumerpull_requesttest,fmt,hi-check,audit,coverage,site,vscode-extension,validate-action,action-consumer,spec-check,corvid-petpull_requesttest,fmt,hi-check,audit,coverage,site,vscode-extension,validate-action,action-consumer,spec-checkcorvid-petpull_requesttest,fmt,hi-check,audit,coverage,site,vscode-extension,validate-action,action-consumer,spec-check,corvid-petpushtest,fmt,hi-check,audit,coverage,site,vscode-extension,validate-action,action-consumer,spec-checkcorvid-petpushtest,fmt,hi-check,audit,coverage,site,vscode-extension,validate-action,action-consumer,spec-checkcorvid-petpushsite,validate-action,spec-checktest,fmt,hi-check,audit,coverage,vscode-extension,action-consumer,corvid-petpushvalidate-action,spec-checktest,fmt,hi-check,audit,coverage,site,vscode-extension,action-consumer,corvid-petworkflow_dispatchtest,fmt,hi-check,audit,coverage,site,vscode-extension,validate-action,action-consumer,spec-checkcorvid-petOn every one of the 192 combinations of the six classify flags the job conditions read, under each of
pull_request,pushandworkflow_dispatch, the required gate is green when every selected job succeeds.Found on the way, not changed here
attest("Record attestation") has been skipped on each of the last 15 pushes tomain, including runs whereRequired CI gatesucceeded. Job-levelsuccess()looks at every transitive dependency, andcorvid-pet, two levels up, is always skipped on pushes. I've left it for its own issue.corvid-pet's status table has no rows forpreflightorlifecycle-gate, and it labels everyskippedas "Not selected". So on a pull request that needs a scoped review, a failed lifecycle gate still gets a passing review summary. The required gate is now red in that case, so merge is blocked, but the review comment is misleading.Test Plan
python3 -S .github/scripts/test-required-ci-gate.py: 29 tests pass.ci.ymlfromorigin/mainfail 65 cases in five tests (contract,needs, CI wiring, the CI: Required CI gate passes when the lifecycle gate fails (skipped jobs read as green) #796 reproduction, and 60 cases wherepreflightorlifecycle-gatefails or is cancelled across the 15 lanes).validate-workflow-runtime-pins.py,validate-release-version.pyandtest-classify-ci-paths.shpass on the changed workflow.fledge lanes run verify: fmt, clippy, check, 2504 unit and 437 integration tests, release build, strict spec check (62/62, 100% coverage), release-candidate tests,ci-gate-test.fledge lanes run pre-pushandfledge trust verify.17e63f5d:Lifecycle gatered on the unapproved draft, soSpecSync implementation readyandRequired CI gateare red.validate-actionran the new tests (29, OK).change check --commit:Required CI gategreen.🤖 Generated with Claude Code
https://claude.ai/code/session_01V3ZZAEiUP7xRJPozhZb6rL