diff --git a/tools/index-watch.py b/tools/index-watch.py index 1f69494..821d66e 100755 --- a/tools/index-watch.py +++ b/tools/index-watch.py @@ -245,8 +245,29 @@ def check_once(state_path, force=False, subject=None, repo=None, legs=None, sha= prev, base = load_state(state_path) if prev == sha and not force: # The only silent-ish path, and it is silent about the SUBJECTS, not about itself. + # + # ⛔ #598: THIS LINE NAMES ITS OWN REMEDY NOW, and the omission was the whole cost. + # `--force` exists and is documented in --help ("run the subject even if main has not + # moved"), and this output — the ONLY output a reader sees when the legs did not run — + # never mentioned it. Measured 2026-09-06: 0 occurrences of "--force" in a + # short-circuit run. + # + # ⚠ WHAT THAT COST, from the field: a pane probing whether index-watch invokes + # verdict-census planted a recording stub and watched it fire on run 1 and NOT on runs + # 2-4. It nearly reported a FALSE NEGATIVE — "this caller does not exist" — because + # nothing here said the legs could be MADE to run. ⇒ The prose was true and complete + # about what happened, and silent about what to do, which is the shape #73 records: + # an absence report that does not name its remedy converts a gap into a wall. + # + # ⚠ EXIT 0 IS DELIBERATELY UNCHANGED. This file's contract already reads "0 main + # unchanged, OR checked and the subject reported clean" — two-valued by declaration, + # not by accident — and twelve files reference this tool. #598 argues that declaring + # it does not make it safe, and that argument stands; it is recorded there, not + # settled here. What is settled: a reader who sees this line now knows the next move. return 0, [f" ok main unchanged at {sha[:8]} — {len(legs)} leg(s) not run" - f" (nothing to re-check)"] + f" (nothing to re-check; --force runs them anyway)", + f" ⚠ this is a SKIP, not a verdict: exit 0 here means the legs did NOT" + f" run. See #598."] codes, all_lines, all_found = [], [], [] for leg in legs: diff --git a/tools/pane-census.py b/tools/pane-census.py index bd356f4..db88b6d 100644 --- a/tools/pane-census.py +++ b/tools/pane-census.py @@ -324,6 +324,27 @@ def main(): # 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. + # ⛔ ANY unrecognised argument, not just one alongside `--self-test`. #607 refused only + # the second, and that was HALF THE PROBE: the gate runs `--zzz-not-a-flag` BARE too, and + # a bare unknown flag fell straight through to the main path — so the tool returned its + # CENSUS VERDICT and the gate read that as "it accepts garbage". + # + # ⚠ HOW THE HOLE HID, and it is the reason this is worth the words: the verdict returned + # depends on LIVE STATE, so the gate's reading of THIS FILE moved without the file + # changing. Measured 2026-09-06, same tree, one hour apart: + # `--zzz-not-a-flag` -> 1 (a divergence was live) ⇒ gate satisfied + # `--zzz-not-a-flag` -> 0 (sources agreed) ⇒ gate: UNVERIFIABLE + # ⇒ #607's fix passed CI only because the fleet happened to diverge that hour. A control + # that holds for an environmental reason is not a control. + # ⚠ Exit 2 is this file's documented "established nothing"; a refusal collides with + # neither 0 nor 1. + _KNOWN = {"--self-test", "--selftest"} + _unknown = [a for a in sys.argv[1:] if a not in _KNOWN] + if _unknown and not ({"--self-test", "--selftest"} & set(sys.argv[1:])): + print(f"\u26d4 VOID \u2014 unrecognised argument(s): {_unknown}. This instrument takes\n" + f" none but --self-test; it reads the pane census and nothing else.\n" + f" NO REMEDY \u2014 there is no flag to pass. Run it bare.", file=sys.stderr) + return 2 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: diff --git a/tools/pipe-exit-scan.py b/tools/pipe-exit-scan.py index d53fdde..56dec00 100755 --- a/tools/pipe-exit-scan.py +++ b/tools/pipe-exit-scan.py @@ -467,6 +467,35 @@ def main(): # 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. + # ⛔ ANY unrecognised argument, not just one alongside `--self-test`. #607 refused only + # the second, and that was HALF THE PROBE: the gate runs `--zzz-not-a-flag` BARE too, and + # a bare unknown flag fell straight through to the main path — so the tool returned its + # CENSUS VERDICT and the gate read that as "it accepts garbage". + # + # ⚠ HOW THE HOLE HID, and it is the reason this is worth the words: the verdict returned + # depends on LIVE STATE, so the gate's reading of THIS FILE moved without the file + # changing. Measured 2026-09-06, same tree, one hour apart: + # `--zzz-not-a-flag` -> 1 (a divergence was live) ⇒ gate satisfied + # `--zzz-not-a-flag` -> 0 (sources agreed) ⇒ gate: UNVERIFIABLE + # ⇒ #607's fix passed CI only because the fleet happened to diverge that hour. A control + # that holds for an environmental reason is not a control. + # ⚠ Exit 2 is this file's documented "established nothing"; a refusal collides with + # neither 0 nor 1. + _KNOWN = {"--self-test", "--selftest", "--transcripts", "--project"} + _av = sys.argv[1:] + _unknown, _skip = [], False + for _i, _a in enumerate(_av): + if _skip: # --project consumes the next token as its VALUE + _skip = False; continue + if _a == "--project": + _skip = True; continue + if _a not in _KNOWN: + _unknown.append(_a) + if _unknown and not ({"--self-test", "--selftest"} & set(_av)): + print(f"\u26d4 VOID \u2014 unrecognised argument(s): {_unknown}. This instrument takes\n" + f" {sorted(_KNOWN)} and nothing else.\n" + f" NO REMEDY \u2014 drop it and run again.", file=sys.stderr) + return 2 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: