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
Pre-existing approval-laundering residual on the merge-guard: the multi-close ambiguity corner of the close/--delete-branch channel. Surfaced during the TEST re-cert of the #1082/#1083 leg-isolation work (PR #1085). Rigorously attributed pre-existing (mutation-proven: under a pre-C-iii simulation the behavior is byte-identical), so NOT a regression from that PR — but it means the close laundering channel is not fully closed by the #1083 fix.
The hole
Approve gh pr close 42 && gh pr close 43 && echo --delete-branch (two bare PR-closes + an echo). The real mint produces ONE token {close, pr 42, bound_flags=['--delete-branch']}. Then executing the escalated real, irreversiblegh pr close 42 --delete-branch → AUTHORIZES. That is the exact close-laundering the #1083 fix set out to close, still open in the ≥2-detectable-close corner.
The two-tier bind fix abstains on ambiguity. Two detectable close legs → _single_detectable_leg returns None (tier-2 abstains on ≥2) → both mint and read fall back to whole-command → both symmetrically over-bind ['--delete-branch'] → the byte-identical re-approval authorizes AND the escalated single authorizes against the [--delete-branch] token.
_collect_pairs collapses both closes to a single (close, 42) key (pr-number extraction is first-match-anywhere), so the multiplicity gate passes.
Fix sketch
Convert the close literal danger arms (pr close\b(?=.*--delete-branch) + the reversed --delete-branch.*close arm) to per-leg matching over the shared leg substrate — the exact #1082 pattern (force-push arms), now applied to close. Consequence: gh pr close 42 && gh pr close 43 && echo --delete-branch classifies not-dangerous (no leg has close+flag together) → no token → runs free; the real single-command gh pr close 42 --delete-branch still gates. This also makes the single-close member (close && echo --delete-branch, #1083) not-dangerous at the danger-determination level — assess interaction with the #1083 two-tier bind fix (likely belt-and-suspenders; the architect should confirm no redundancy conflict).
CAUTION — read danger-floor edit + _collect_pairs: (a) per-leg close matching must still gate every legitimate same-leg dangerous close (gh pr close 42 --delete-branch, cd /repo && gh pr close 42 --delete-branch, -d/--delete-branch spellings, quoted separators, bash -c single-leg) — its own no-new-under-block sweep; (b) assess whether the _collect_pairs multi-key collapse needs its own fix for other shapes, or is mooted by the per-leg conversion for this case.
Also: a test-coverage gap this exposed
The #1083 canary set tested the ambiguous form as an execution against a clean []-token (correctly DENY) but NOT as an approval source (which mints the ['--delete-branch'] token). §12.9's "DENY — fail-safe retained" row has the same gap. The fix (whichever PR) should add the approval-source direction.
Provenance
Surfaced by the TEST engineer during the #1082/#1083 leg-isolation re-cert (PR #1085); mutation-proven pre-existing. The close-arm analogue of #1082; same cross-leg-lookahead-on-a-danger-arm family as #1078 (union arm), #1082 (force-push arms), and #1083 (bind surfaces).
Class
Pre-existing approval-laundering residual on the merge-guard: the multi-close ambiguity corner of the close/
--delete-branchchannel. Surfaced during the TEST re-cert of the #1082/#1083 leg-isolation work (PR #1085). Rigorously attributed pre-existing (mutation-proven: under a pre-C-iii simulation the behavior is byte-identical), so NOT a regression from that PR — but it means the close laundering channel is not fully closed by the #1083 fix.The hole
Approve
gh pr close 42 && gh pr close 43 && echo --delete-branch(two bare PR-closes + an echo). The real mint produces ONE token{close, pr 42, bound_flags=['--delete-branch']}. Then executing the escalated real, irreversiblegh pr close 42 --delete-branch→ AUTHORIZES. That is the exact close-laundering the #1083 fix set out to close, still open in the ≥2-detectable-close corner.Why it survives the #1083 fix
Two interacting roots:
pr close\b(?=.*--delete-branch)looks ahead across legs into the echo → whole-command classifies dangerous. This is the SAME cross-leg-lookahead root as merge-guard: literal force-push arms' .* span crosses leg boundaries — push … && rm --force/-f … over-blocked (one form permanently) #1082, but on the close arms. merge-guard: literal force-push arms' .* span crosses leg boundaries — push … && rm --force/-f … over-blocked (one form permanently) #1082's fix converted the force-push literal arms to per-leg; it did not touch the close arms._single_detectable_legreturns None (tier-2 abstains on ≥2) → both mint and read fall back to whole-command → both symmetrically over-bind['--delete-branch']→ the byte-identical re-approval authorizes AND the escalated single authorizes against the[--delete-branch]token._collect_pairscollapses both closes to a single(close, 42)key (pr-number extraction is first-match-anywhere), so the multiplicity gate passes.Fix sketch
Convert the close literal danger arms (
pr close\b(?=.*--delete-branch)+ the reversed--delete-branch.*closearm) to per-leg matching over the shared leg substrate — the exact #1082 pattern (force-push arms), now applied to close. Consequence:gh pr close 42 && gh pr close 43 && echo --delete-branchclassifies not-dangerous (no leg has close+flag together) → no token → runs free; the real single-commandgh pr close 42 --delete-branchstill gates. This also makes the single-close member (close && echo --delete-branch, #1083) not-dangerous at the danger-determination level — assess interaction with the #1083 two-tier bind fix (likely belt-and-suspenders; the architect should confirm no redundancy conflict).CAUTION — read danger-floor edit +
_collect_pairs: (a) per-leg close matching must still gate every legitimate same-leg dangerous close (gh pr close 42 --delete-branch,cd /repo && gh pr close 42 --delete-branch,-d/--delete-branchspellings, quoted separators, bash -c single-leg) — its own no-new-under-block sweep; (b) assess whether the_collect_pairsmulti-key collapse needs its own fix for other shapes, or is mooted by the per-leg conversion for this case.Also: a test-coverage gap this exposed
The #1083 canary set tested the ambiguous form as an execution against a clean
[]-token (correctly DENY) but NOT as an approval source (which mints the['--delete-branch']token). §12.9's "DENY — fail-safe retained" row has the same gap. The fix (whichever PR) should add the approval-source direction.Provenance
Surfaced by the TEST engineer during the #1082/#1083 leg-isolation re-cert (PR #1085); mutation-proven pre-existing. The close-arm analogue of #1082; same cross-leg-lookahead-on-a-danger-arm family as #1078 (union arm), #1082 (force-push arms), and #1083 (bind surfaces).