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
{{ message }}
Repository navigation
Structural checks: prevent new prose restatements and cycle-decision bypass #362
Deferred preventive half of the root-cluster remediation on #361. The current sites are fixed there; this issue covers the guard against future authoring.
Root cause
Prose-as-contract. The watch loop's operative contract was expressed as free prose duplicated across seven-plus independent copies, with no single authoritative statement and no enforcement at the site that consumes it. Each copy was an independent drift surface.
Three consecutive review iterations each found a different copy drifted, or a different prose assertion the executable never enforced:
Pre-PR local review — the re-arm seed was specified after the dispatch it must precede.
Post-PR cycle 0 — arm-expiry re-seeding reopened the blind window; the snapshot-seeded APPROVED_PRESENT suppressed a standing approval.
Post-PR cycle 1 — ADR-0029:61 still instructed the "re-capture a seed" that cycle 0 had removed (and :53 carried a second copy of the same wrong ordering); the prose-declared six-cycle floor was never enforced by loop-state.sh.
max_remediation_cycles floor becomes a named constant owned and enforced by plugin/skills/github-review-loop/scripts/loop-state.sh, exposed via a floor subcommand. Every prose site drops the literal and cites the script. This closes the class for the number: no live prose states it, so no prose statement can diverge from the enforced value.
The seed-capture rule collapses to one named INVARIANT block in plugin/skills/github-review-loop/SKILL.md; every other site, including ADR-0029, is reduced to a reference.
What this issue covers
Two structural checks in tools/policy_check.sh, neither of which exists today:
New-caller bypass. Detect a caller that re-implements the cycle arithmetic instead of routing through loop-state.sh cycle-decision, and therefore never reaches the floor guard. This is the rule-7 absence defect named in tests/policy/safety-cycle-floor-single-source.json — a presence pin cannot see a site that simply does not call the thing.
New prose restatement. Detect a newly-authored copy of a single-sourced contract. feat!: make the post-PR watch the default with a bounded idle window #361 deletes every current restatement, but nothing makes a future one unrepresentable, so the seed-rule half of that remediation narrows the class rather than eliminating it. That partial closure is recorded as a residual in ADR-0029 rather than claimed as a fix.
Bounded impact
No current caller undercuts the floor, and after #361 no live prose restates the seed rule or the number. The exposure is future-authoring only, and it is invisible to CI — which is precisely why it warrants a structural check rather than another review pass.
#361 already changes tools/, and validator regressions are the worst failure class in this repo: a broken check is silent and leaves the suite green through real defects. Adding validator surface for preventive-only value, inside an already-large MAJOR release, trades a real risk for a hypothetical one.
Deferred preventive half of the root-cluster remediation on #361. The current sites are fixed there; this issue covers the guard against future authoring.
Root cause
Prose-as-contract. The watch loop's operative contract was expressed as free prose duplicated across seven-plus independent copies, with no single authoritative statement and no enforcement at the site that consumes it. Each copy was an independent drift surface.
Three consecutive review iterations each found a different copy drifted, or a different prose assertion the executable never enforced:
APPROVED_PRESENTsuppressed a standing approval.ADR-0029:61still instructed the "re-capture a seed" that cycle 0 had removed (and:53carried a second copy of the same wrong ordering); the prose-declared six-cycle floor was never enforced byloop-state.sh.The recurrence rate was itself the signal.
What #361 fixes
max_remediation_cyclesfloor becomes a named constant owned and enforced byplugin/skills/github-review-loop/scripts/loop-state.sh, exposed via afloorsubcommand. Every prose site drops the literal and cites the script. This closes the class for the number: no live prose states it, so no prose statement can diverge from the enforced value.plugin/skills/github-review-loop/SKILL.md; every other site, including ADR-0029, is reduced to a reference.What this issue covers
Two structural checks in
tools/policy_check.sh, neither of which exists today:loop-state.sh cycle-decision, and therefore never reaches the floor guard. This is the rule-7 absence defect named intests/policy/safety-cycle-floor-single-source.json— a presence pin cannot see a site that simply does not call the thing.Bounded impact
No current caller undercuts the floor, and after #361 no live prose restates the seed rule or the number. The exposure is future-authoring only, and it is invisible to CI — which is precisely why it warrants a structural check rather than another review pass.
Why deferred rather than done in #361
#361 already changes
tools/, and validator regressions are the worst failure class in this repo: a broken check is silent and leaves the suite green through real defects. Adding validator surface for preventive-only value, inside an already-large MAJOR release, trades a real risk for a hypothetical one.Review threads
References
plugin/governance/remediation-doctrine.md— Closed-by-Construction Acceptance Test; Cross-Iteration Same-Surface Recurrence; Defer-with-Scopetests/policy/README.md— pin-authoring contract, rule 7 (absence defects need a structural check, not a presence pin)CLAUDE.md— the "unprotected coupling (P3)" pitfalldocs/adr/0029-default-pr-watch-and-idle-window-lifecycle.md