Skip to content

#598 names its remedy; and #607 was half a fix — the gate probes garbage bare too - #613

Merged
jobordu merged 2 commits into
mainfrom
teamlead/indexwatch-names-force
Sep 6, 2026
Merged

#598 names its remedy; and #607 was half a fix — the gate probes garbage bare too#613
jobordu merged 2 commits into
mainfrom
teamlead/indexwatch-names-force

Conversation

@jobordu

@jobordu jobordu commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Two commits, one investigation. The second was found by the first appearing to regress something it
did not.

1. #598 — the short-circuit names its own remedy

--force exists and is documented in --help ("run the subject even if main has not moved"), and
the only output a reader sees when the legs did not run never mentioned it. Measured: 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 said the legs could be made
to run.

⇒ The prose was true and complete about what happened, and silent about what to do. That is
#73's shape: an absence report that does not name its remedy converts a gap into a wall.

run 2 (short-circuit)   exit 0, now names --force and declares itself a SKIP
--force, same tree      exit 1, legs actually run

Exit 0 is deliberately unchanged, and that is a ruling. 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; that argument stands and is recorded there. What is settled here: a reader who sees this
line now knows the next move
, which is the harm the issue actually recorded.

2. ⛔ #607 was half a fix — the gate probes garbage bare too

I found this because my change appeared to regress pane-census. ⚠ The control says otherwise:
three runs at origin/main with my change absent read identically. Not a regression — the state
had flipped under both.

The mechanism is the finding. #607 refused an unknown flag only alongside --self-test. The
gate also runs --zzz-not-a-flag bare, and a bare unknown flag fell straight through to the main
path — so each tool returned its own census/scan verdict and the gate read that as "it accepts
garbage"
.

⇒ That verdict depends on live state, so the gate's reading of an unchanged file moved on its
own:

pane-census --zzz-not-a-flag  ->  1   (a divergence was live)   gate satisfied
pane-census --zzz-not-a-flag  ->  0   (sources agreed)          gate UNVERIFIABLE

So #607 passed CI only because the fleet happened to diverge that hour. A control that holds
for an environmental reason is not a control
— which is the proposition the gate exists to enforce,
and my fix was an instance of violating it.

pipe-exit-scan had the same latent hole, passing for the same kind of accident: bare and
garbage both exit 1 because it happens to have findings. If those ever cleared it would exit 0 and go
UNVERIFIABLE with nothing changed.

Both now refuse any unrecognised argument. Known flags derived, not assumed:

pane-census      --self-test/--selftest
pipe-exit-scan   --self-test/--selftest, --transcripts, --project <value>

--project consumes the next token as its value; the guard skips it, and --transcripts is
re-run and still reaches the main path. Exit 2 is each file's own documented "established nothing".

pane-census      bare=0 garbage=2 self=0 self+garbage=2
pipe-exit-scan   bare=1 garbage=2 self=0 self+garbage=2

Measured — three consecutive runs, stable for a structural reason

44 control(s) passed · 0 FAILED · 0 UNESTABLISHED · 1 UNVERIFIABLE

The survivor is pretooluse-guard.py, a live PreToolUse hook — harness configuration, the
operator's. UNVERIFIABLE by choice.

test_pane_census · test_pipe_exit_scan · test_index_watch exit 0
scripts/exit-code-gate.sh tools 'test_*.py' exit 0
scripts/check-tools-index.py exit 0

🤖 Generated with Claude Code

https://claude.ai/code/session_01DTMf4EvaTEnDKXY47efRZZ

Jonathan Borduas and others added 2 commits September 6, 2026 10:14
`--force` exists and is documented in --help — "run the subject even if main has
not moved" — and the ONLY output a reader sees when the legs did not run never
mentioned it. Measured: 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. That is #73's shape: an absence report that does not name its remedy converts
a gap into a wall.

Two-poled on an unchanged tree:
    run 2 (short-circuit)  exit 0, now names --force and declares itself a SKIP
    --force, same tree     exit 1, legs actually run

⛔ EXIT 0 IS DELIBERATELY UNCHANGED, and this is a ruling, not a deferral. 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; that
argument stands and is recorded there. What is settled here: a reader who sees
this line now knows the next move, which is the harm the issue actually recorded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DTMf4EvaTEnDKXY47efRZZ
… ignored it

⛔ I FOUND THIS BY MY OWN CHANGE APPEARING TO REGRESS SOMETHING IT DID NOT.
pane-census read UNVERIFIABLE on my branch; the CONTROL — three runs at
origin/main, my change absent — read IDENTICALLY. ⇒ Not a regression. The state
had FLIPPED under both.

★ AND THE MECHANISM IS THE FINDING. #607 refused an unknown flag only ALONGSIDE
`--self-test`. The gate also runs `--zzz-not-a-flag` BARE, and a bare unknown
flag fell straight through to the main path — so each tool returned its own
CENSUS/SCAN verdict, and the gate read that as "it accepts garbage".

⇒ That verdict depends on LIVE STATE, so the gate's reading of an UNCHANGED FILE
moved on its own. Measured, same tree, one hour apart:

    pane-census --zzz-not-a-flag -> 1   (a divergence was live)  gate satisfied
    pane-census --zzz-not-a-flag -> 0   (sources agreed)         gate UNVERIFIABLE

⛔ SO #607 PASSED CI ONLY BECAUSE THE FLEET HAPPENED TO DIVERGE THAT HOUR. A
control that holds for an environmental reason is not a control — which is the
proposition the gate exists to enforce, and my fix was an instance of violating
it.

⚠ pipe-exit-scan had the SAME latent hole and was passing for the SAME kind of
accident: bare and garbage both exited 1 because it happens to have findings. If
those ever cleared it would exit 0 and go UNVERIFIABLE with nothing changed.

⇒ Both now refuse ANY unrecognised argument. Known flags derived, not assumed:
    pane-census      --self-test/--selftest
    pipe-exit-scan   --self-test/--selftest, --transcripts, --project <value>
⚠ `--project` consumes the NEXT token as its value; the guard skips it, and
`--transcripts` is re-run above and still reaches the main path.
⚠ Exit 2 is each file's own documented "established nothing".

    pane-census      bare=0 garbage=2 self=0 self+garbage=2
    pipe-exit-scan   bare=1 garbage=2 self=0 self+garbage=2

MEASURED, three consecutive runs, now STABLE for a structural reason:
    44 control(s) passed · 0 FAILED · 0 UNESTABLISHED · 1 UNVERIFIABLE

test_pane_census 0 · test_pipe_exit_scan 0 · test_index_watch 0 ·
exit-code-gate 0 · check-tools-index 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DTMf4EvaTEnDKXY47efRZZ
@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 35 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 37f0a397-cf5c-4e27-a7b5-5b71a32c70ca

📥 Commits

Reviewing files that changed from the base of the PR and between 8a9eeef and 03278ee.

📒 Files selected for processing (3)
  • tools/index-watch.py
  • tools/pane-census.py
  • tools/pipe-exit-scan.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jobordu
jobordu merged commit 5966a08 into main Sep 6, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant