From bdf0abb4712a05614b85d849242f57cf92bc4d03 Mon Sep 17 00:00:00 2001 From: Jonathan Borduas Date: Sun, 6 Sep 2026 05:20:42 +0100 Subject: [PATCH] pane-census, pipe-exit-scan: refuse a flag alongside --self-test, so the control counts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both matched `--self-test` and DISCARDED the rest of argv. The gate said why that is not a control: ⚠ UNVERIFIABLE — `--self-test --zzz-not-a-flag` exits 0. ⛔ The flag is matched and the rest DISCARDED, so a control result here describes an invocation that was only half read. ⇒ MEASURED, and the gain is larger than the bucket move: BEFORE 41 control(s) passed · 3 UNESTABLISHED · 5 UNVERIFIABLE AFTER 43 control(s) passed · 3 UNESTABLISHED · 3 UNVERIFIABLE Both had REAL self-tests all along. They were not counted because the gate could not establish the flag had been read. ⇒ The repair did not add a control; it made two existing ones legible. pane-census bare=1 garbage=1 self-test=0 self-test+garbage=2 pipe-exit-scan bare=1 garbage=1 self-test=0 self-test+garbage=2 ⚠ EXIT 2 IS CORRECT AND UNAMBIGUOUS FOR THESE TWO, and I checked before using it. Both contracts already read `2 established nothing`, and a half-read invocation establishes nothing. That check mattered — see below. ⛔ WHAT I DID NOT TOUCH, AND WHY EACH IS DIFFERENT: discriminates.py ITS EXIT SPACE IS FULL. 0 discriminated · 2 non-discriminating · 3 control failed · 4 uninterpretable. A refusal needs a code that is not a verdict, and there is none free. Its own header already records the hazard (#58, the exit-2 collision) and intercepts `--self-test` BEFORE parse_args for exactly that reason. Choosing a new code changes a reasoned contract on another role's tool — a decision, not a repair. fleet-identity.py Shape A: bare, garbage and `--self-test` ALL exit 0. It needs an argv surface built, not a refusal added. pretooluse-guard A LIVE PreToolUse hook. Its header: an addition "changes a running mechanism". Harness configuration is the operator's. It stays UNVERIFIABLE BY CHOICE, and that is worth recording rather than fixing. gate --self-test 0 · exit-code-gate 0 · check-tools-index 0 · test_pane_census 0 · test_pipe_exit_scan 0. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01DTMf4EvaTEnDKXY47efRZZ --- tools/pane-census.py | 14 ++++++++++++++ tools/pipe-exit-scan.py | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/tools/pane-census.py b/tools/pane-census.py index cc1270e..bd356f4 100644 --- a/tools/pane-census.py +++ b/tools/pane-census.py @@ -317,7 +317,21 @@ def chk(label, got, want): def main(): + # ⛔ AN UNRECOGNISED FLAG ALONGSIDE `--self-test` MUST REFUSE, not be discarded. The + # gate measured this file as UNVERIFIABLE: `--self-test --zzz-not-a-flag` exited 0, so + # "the flag is matched and the rest DISCARDED — a control result here describes an + # invocation that was only half read." ⇒ A control whose invocation cannot be shown to + # have happened is not a control. Measured 2026-09-06. + # ⚠ Exit 2 is correct and unambiguous here: this file's contract already reads + # `2 established nothing`, and a half-read invocation establishes nothing. if "--self-test" in sys.argv or "--selftest" in sys.argv: + _extra = [a for a in sys.argv[1:] if a not in ("--self-test", "--selftest")] + if _extra: + print(f"\u26d4 VOID \u2014 unrecognised argument(s) alongside --self-test: {_extra}.\n" + f" The controls take no other flags, and running them while ignoring an\n" + f" argument would report a pass for an invocation that was only half read.\n" + f" NO REMEDY \u2014 run `--self-test` alone.", file=sys.stderr) + return 2 return self_test() rows, err = panes_from_daintree() status_ids = getattr(panes_from_daintree, "_status_ids", None) diff --git a/tools/pipe-exit-scan.py b/tools/pipe-exit-scan.py index 91e449f..d53fdde 100755 --- a/tools/pipe-exit-scan.py +++ b/tools/pipe-exit-scan.py @@ -460,7 +460,21 @@ def main(): # nobody would guess is worse than an absent one, because its existence has # been ASSERTED. A reviewer pointed the tool at the fixture, got the normal # scan, and nearly recorded that as a clean negative. + # ⛔ AN UNRECOGNISED FLAG ALONGSIDE `--self-test` MUST REFUSE, not be discarded. The + # gate measured this file as UNVERIFIABLE: `--self-test --zzz-not-a-flag` exited 0, so + # "the flag is matched and the rest DISCARDED — a control result here describes an + # invocation that was only half read." ⇒ A control whose invocation cannot be shown to + # have happened is not a control. Measured 2026-09-06. + # ⚠ Exit 2 is correct and unambiguous here: this file's contract already reads + # `2 established nothing`, and a half-read invocation establishes nothing. if "--self-test" in sys.argv or "--selftest" in sys.argv: + _extra = [a for a in sys.argv[1:] if a not in ("--self-test", "--selftest")] + if _extra: + print(f"\u26d4 VOID \u2014 unrecognised argument(s) alongside --self-test: {_extra}.\n" + f" The controls take no other flags, and running them while ignoring an\n" + f" argument would report a pass for an invocation that was only half read.\n" + f" NO REMEDY \u2014 run `--self-test` alone.", file=sys.stderr) + return 2 return selftest() if "--transcripts" in sys.argv: project = None