Finding
tools/index-watch.py exits 0 in two situations a caller cannot tell apart:
| exit |
meaning |
how it reads to a caller |
| 0 |
legs ran, record is current |
✅ verified |
| 0 |
main has not moved — legs NOT RUN |
✅ verified (wrong) |
Measured 2026-09-05, three consecutive invocations in the same tree, nothing edited between:
run 1 exit=1 FINDING — the indexed population moved; the record no longer answers it
⛔ use-not-mention.py: bytes changed (1a86d493 -> b1bb82a5)
⛔ wake-yield.py: bytes changed (33ada381 -> f98f7afc)
⚠ 11 STANDING environmental negative(s)
run 2 exit=0 "ok main unchanged at c60af675 — 2 leg(s) not run (nothing to re-check)"
quiet
run 3 exit=0 quiet
index-watch.py:211 writes {"sha", "findings"} after reporting. It is a stateful watch:
it short-circuits when main has not moved since the recorded sha. So the first read consumed
the finding, and every read after it reports quiet.
Why this is worth a number
The repo's convention is that exit 2 means "established nothing" and must never be read as
"all clear." This is the same hazard arriving through the one exit code that is supposed to
be safe. 0 here means "I did not check", and the tool says so in prose — 2 leg(s) not run — while the exit code says the opposite. A caller reading the exit code, which is what a
caller is for, gets the wrong answer with no signal that it is wrong.
⚠ It is also self-erasing: the run that finds drift is the run that records the sha which
suppresses it. Re-running to confirm a finding destroys the finding. That is the property that
made me misreport it — I ran it a second time to check, got quiet, and briefly concluded the
first result was noise.
★ CONTROL, so this is not a claim about one tool: origin/main's copy exits 0 with the same
quiet short-circuit. This is the current committed behaviour, not a local artifact.
Not proposed as a fix, because the shape of the fix is the decision
Three options, and they are not equivalent:
- A distinct exit code for "skipped" — e.g. 3, or reuse 2 since "not run" is
"established nothing." Honest, and breaks every existing caller that treats non-zero as a
finding.
- Do not record the sha until the caller acknowledges — keeps the finding reachable, and
turns a watch into a queue with all that implies.
- Leave it, and make the CALLER responsible for reading the prose. ⛔ This is what is in
place now, and it is what failed.
Option 1 is the only one that survives a caller who reads nothing but the exit code — which is
the caller this repo actually has.
Close condition
Caller: python3 tools/index-watch.py; echo $? twice in a row on an unmoved main — the two
exits must not both be 0.
Filed by TEAMLEAD, session 15b69750. Surfaced while verifying a claim I had put in a commit
message without reading the output; the false claim is recorded at
#597 (comment).
Finding
tools/index-watch.pyexits 0 in two situations a caller cannot tell apart:Measured 2026-09-05, three consecutive invocations in the same tree, nothing edited between:
index-watch.py:211writes{"sha", "findings"}after reporting. It is a stateful watch:it short-circuits when
mainhas not moved since the recorded sha. So the first read consumedthe finding, and every read after it reports
quiet.Why this is worth a number
The repo's convention is that exit 2 means "established nothing" and must never be read as
"all clear." This is the same hazard arriving through the one exit code that is supposed to
be safe.
0here means "I did not check", and the tool says so in prose —2 leg(s) not run— while the exit code says the opposite. A caller reading the exit code, which is what acaller is for, gets the wrong answer with no signal that it is wrong.
⚠ It is also self-erasing: the run that finds drift is the run that records the sha which
suppresses it. Re-running to confirm a finding destroys the finding. That is the property that
made me misreport it — I ran it a second time to check, got
quiet, and briefly concluded thefirst result was noise.
★ CONTROL, so this is not a claim about one tool:
origin/main's copy exits 0 with the samequietshort-circuit. This is the current committed behaviour, not a local artifact.Not proposed as a fix, because the shape of the fix is the decision
Three options, and they are not equivalent:
"established nothing." Honest, and breaks every existing caller that treats non-zero as a
finding.
turns a watch into a queue with all that implies.
place now, and it is what failed.
Option 1 is the only one that survives a caller who reads nothing but the exit code — which is
the caller this repo actually has.
Close condition
index-watch.pyreturns an exit code that distinguishes legs ran and were clean fromlegs not run, and
tools/README.mdrecords which code means which.short-circuit fires, asserting the codes DIFFER.
Caller:
python3 tools/index-watch.py; echo $?twice in a row on an unmoved main — the twoexits must not both be 0.
Filed by TEAMLEAD, session
15b69750. Surfaced while verifying a claim I had put in a commitmessage without reading the output; the false claim is recorded at
#597 (comment).