Four findings, all upheld, and the first was a live bug I shipped.
1. R-b's non-zero handling was unreachable. scripts/gate runs under
`set -eu`, so the bare helper invocation killed the shell at exit 1
or 2 and neither `sigint_status=$?` nor the refusal messages ever
ran; an unexecutable helper would have escaped as raw 126/127 rather
than boundary error 2. Reproduced before fixing.
The first repair was ALSO wrong, and worse: `if ! helper; then
sigint_status=$?; fi` captures the status of the NEGATED condition,
which is always 0, so the gate printed the ignored diagnosis and
then ran the entire suite. The working shape is `helper ||
sigint_status=$?` --- failure handled, so `set -e` does not fire and
`$?` is the helper's own --- which is the idiom the helper already
uses internally. Statuses 1 and 2 pass through unchanged; everything
else, including 126/127, maps to 2 at the boundary and is never
reported as "SIGINT is ignored".
The guard also moved to immediately after the worktree resolves,
before any log directory, ambient root or tmpdir exists, so a
refused run leaves nothing behind.
2. The behaviour had no durable coverage, which is exactly why 27
passing gate tests missed both bugs. Four rows added: helper safe,
helper ignored, helper error (and never ignored), and gate refusal
before stage 1. Ignored-SIGINT is simulated with `trap "" INT`,
which is the real mechanism --- SIG_IGN inherited across fork and
surviving exec --- not a stand-in. Verified to bite: mutating the
gate back to either shipped bug fails
gate_refuses_to_start_when_sigint_is_ignored and nothing else.
3. The ledger now records the implementation, both bugs, the four rows
and their mutation check.
4. A7 is recorded SATISFIED BY DISCLOSURE, which is the fallback
revision 12 allows when no non-Linux unix is reachable. The earlier
"stays open" contradicted the approved contract and is withdrawn.
Tried: Linux x86_64, all three outcomes, all consumers. Not tried:
every non-Linux unix. Claimed: POSIX shell only, no /proc, no
sigaction --- labelled a contract argument, not a measurement.
The full default gate passes all eight stages foreground; it caught a
rustfmt violation in the new test code on the first attempt, which is
the guard-and-gate arrangement working as intended.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai