Repository navigation
fix(gates): a mid-stage decision is not the stage approval (#477) - #483
Merged
Merged
Conversation
The approved-over-a-failing-gate flag (#207) read any CONFIRMED row of stage N as the approval, so a stage still in progress was flagged the moment any question in it was answered. New stage_exit_recorded counts an explicit exit row ("Stage N approved", "Build plan approved") or a CONFIRMED decision for a later stage. Stage 3/4 gate checks unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
Rule 2 now needs the stage's own CONFIRMED rows plus a later stage up to
6, and skips N/A / skip / no-cutover rows, so an early Stage-7 "no
cutover" row or a forward-filed Stage-6 decision no longer flags a
mid-build Stage 5. Rule 1 accepts em/en dashes and "Approved: Stage N",
and its short form is limited to an artifact-noun allowlist, so domain
decisions ("Requests over 5k must be approved") and "Stage 40 approved"
no longer match. T17 grows to 16 cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
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 #477
Direct lane (changes to
skills/,bug-logs/,bin/,project-bin/,project-tests/, pipelines)What changed and why (one paragraph):
The #207 check prefixes a FAIL with
APPROVED OVER A FAILING GATEwhen the register says the stage was approved. It askedhas_confirmed_decision "$stage", which accepts any CONFIRMED Decisions row whose Stage cell is N. So a stage still being worked on raised the flag the moment the user answered any question in it. The issue's field case was| 5 | Sub-agents run on Sonnet | CONFIRMED | user in chat |on a mid-build Stage 5.status.shthen printedWATCH APPROVED OVER A FAILING GATE: Stage 5and a NEXT telling the lead to re-open an approval nobody gave, which buried the real gap: the PENDING LOOK/sweep/journeys/coherence obligations. This PR addsstage_exit_recorded N, used only by that flag. It counts a stage as approved on either of two pieces of evidence, both in CONFIRMED rows of the Decisions table, with the same table scoping and the same field-anchoredCONFIRMED(dated statuses allowed) ashas_confirmed_decision:Stage N approved/Stage N exit…/Stage N gate: signed off/… closed|complete|done|passed. Separators may be spaces,:,-, or an em or en dash, e.g.Stage 4 — approved with conditions. The dashes are written as an awk alternation, not inside a bracket class, so POSIX awk handles the bytes; checked under gawk, mawk and original-awk.Approved: Stage N ….Gate approved|signed off|passed|closed, withgateas the first word.<artifact> approved|signed off, where the artifact comes from a fixed list: build plan, plan, blueprint, architecture, design (system), wireframes, scope, triage, BRDs, requirements. Domain decisions such asRequests over 5k must be approved,Status values: draft, submitted, approvedorApproval gate closed after 30 daystherefore never match, and neither doesStage 40 approved.bin/lib/artifact-check.shalready derives the register's rank from CONFIRMED rows. Stage 7 is excluded, and so is any later row reading N/A / skip / no cutover.checkpoint-cutover.mdandexisting-app-change.mdtell projects to writeNo legacy system, no cutoverearly, and that is not evidence Stage 5 was signed off. A forward-filed decision never "approves" a stage that has no rows of its own.has_confirmed_decisionand the Stage 3/4 gate checks are unchanged: there, any CONFIRMED row is the evidence that the stage's interview was held. Every verdict and exit code is unchanged. The only wording change is the flag's note,Stage N is approved in PROJECT.mdinstead ofis CONFIRMED in; the summary linestatus.shgreps (^Approved over a failing gate:) is untouched.The documented rule is ambiguous, so this picks the safest reading.
conversion-runbook.md§2 closes a gate on "its ✋ decisionsCONFIRMEDandgate-check.shrun with its output pasted". §1 step 5 writes every gate decision toPROJECT.mdasCONFIRMED. The register formatinit-project.shwrites is| Stage | Decision | Status | Notes |. Nowhere is there a dedicated stage-exit row, and no CAC checkpoint writes one. So "Stage N CONFIRMED" can mean "a ✋ decision of Stage N was confirmed" (the Stage 3/4 gates' reading, and #207's) or "Stage N was signed off" (what the flag's wording claims). I read it as sign-off evidence: an explicit exit row or a later stage's decisions. That kills the #477 false positive and keeps the #207 true positive. A project that skips ahead without ever writing an exit row is still flagged, through rule 2. What it gives up: a mid-stage gate decision intended as the approval is not flagged until the project moves on. Residual: a stage that has its own mid-stage rows and a forward-filed decision for a later stage (≤ 6) is still flagged. Only an exit row written by the checkpoint can tell those apart. The FAIL verdict and exit code stay visible either way.Field evidence (rule 4):
Reported by MendixMau on a requirements-driven field project (Mendix 11.13.0, toolkit
ecb918c, 2026-10-20): the flag sat over a FAIL produced by two mid-stage decisions (sub-agent model, test depth). The register row in the fixture is quoted verbatim from the issue. Reproduced on master with that row over a failing Stage 4 (Stage 4 stands in for 5, because its FAIL needs only a plan without closing rows and no harness obligations): the note and the summary both readAPPROVED OVER A FAILING GATE — Stage 4 is CONFIRMED. With the fix, no flag; an explicit exit row or a later-stage decision still flags. The author session could not use any client project, so a re-run ofgate-check.sh . 5andstatus.sh . --briefon the reporting project is owed by the maintainer.Impact
bin/gate-check.shonly (one new function, one call site). It readsPROJECT.md's Decisions table as before. Producers: §1 step 5 / the CAC checkpoints (decision rows), and the next stage's own decisions (rule 2). No mandatory step writes an explicit exit row today. Rule 2 needs none, and that is why it is there.status.shis unchanged and reads the same summary line. No ordering constraint against #469/#470/#471 beyond a trivialCHANGELOG.mdline merge.bin/render-routing.sh --checkclean, same numbers).awkpass overPROJECT.md, only for a stage that FAILs. Negligible./Users/and/home/user: 0 hits;LEAKGUARD_ALLOW_NO_DENYLIST=1 bin/check-no-client-data.shclean)gate-check.sh(mostly the comment); the rest is the fixture and CHANGELOGtests/wave2/test-bug03-gates.sh bin/gate-check.shgives 47/47. T17 has 16 cases:Stage 4 approved, a datedStage 4 gate: signed off,Build plan approved,Stage 4 — approved with conditions,Approved: Stage 4 build plan, and the stage's own rows plus a later-stage row;Purchase requests above 5k need approval,Status values: draft, submitted, approved,Requests over 5k must be approved,Approval gate closed after 30 days);Stage 40 approved; an ASSUMED exit row or another stage's row; an Open-questions row; and, over a failing Stage 5 with no rows of its own,| 7 | No legacy system, no cutover | CONFIRMED |and| 6 | Test depth: journeys per module | CONFIRMED |.gate-check.sh(copied underbin/soTOOLKIT_DIRresolves the same) T17 gives 7 FAIL. On the first head of this PR (e8db9ef) it gave 8 FAIL: the review's two Stage-5 false positives, the dash andApproved:wordings, and the domain/Stage 40matches. The gate fixtures that grepCONFIRMEDall pass:test-bug02-register.sh8/0,test-closeout.sh34/0,test-stage-header.sh13/0,test-stage-p.sh14/0,test-wireframe-count.sh5/0,test-wrong-verdicts.sh20/0,test-status-existing-app.sh bin/status.sh27/27.bin/check-scripts.sh,bin/check-portability.sh,bin/render-routing.sh --checkandbin/check-pr-discipline.sh origin/masterare clean.$REGISTERlogic, unchanged. Platforms: POSIX awk only (split,tolower, dynamic regex), no gawk extensions (check-portability.shclean).CHANGELOG.mdline appended, crediting MendixMauLeft open: the issue's other option, a dedicated
Stage N approvedrow written by the CAC checkpoint, would make rule 1 the normal path. That changesskills/checkpoints/and the runbook, which are agent-read text that needs its own A/B per the authoring rules, so it is not in this PR.https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
Generated by Claude Code