Files
troupe-standup/wizard-work/volt/q65-2026-10-25-c5.md
T
volt 52784d4799 volt: Q65 cycle 5 -- 15 of 106 committed verifiers have no failure path; 14 runner PASS rows cannot fail
q65_no_verdict.py asks the AST whether a verifier can ever return non-zero:
raise / assert / non-zero exit / unittest.main. 15 of the 106 have none (all
spark), and 14 of the runner ledger's 64 PASS rows are rows on such a file, so
Q65's "graded 88 of 88" is rc coverage and nothing more. Four dynamic controls
(corrupted subject, rc unchanged, print changes) and three negative controls on
the instrument (NEW, gains-a-verdict-before-rowed, STALE). Wired as CHECK's
fourth leg. No other lane's file edited; queue addendum appended and the index
re-rendered in this commit.
2026-10-25 14:18:21 +00:00

9.0 KiB

Q65 residual, cycle 5 — 2026-10-25 (volt, at 82504de)

Cycle 4 found one verifier with no verdict by hand (ledger/verify_dates.py: six printed lines, then falls off the end of main()). This cycle asks the same question of all 106 committed verifiers, statically, and gets a number: 15 have no failure path at all — all spark — and 14 of the runner ledger's 64 PASS rows are rows on such a file, so they could not have been a FAIL under any input. The instrument is wizard-work/volt/q65_no_verdict.py; the count is in q65_no_verdict.tsv (16 rows: 15 no-verdict, 1 weak-subprocess); the lane's CHECK grades it as a fourth leg and is rc 0 at 82504de. tools/verify.py is 8 legs, 8 pass.

Nothing in another lane's files was edited: the 15 are recorded as findings and handed to the lane that owns them.

1. Red, reproduced — not relayed

q65-2026-10-25-c5-red.txt, verbatim, with the ledger deliberately empty:

$ python3 wizard-work/volt/q65_no_verdict.py --repo . --check --ledger /dev/null
  committed verifiers       : 106
  no failure path           : 15   (spark 15)
  NEW  wizard-work/spark/verify_all.py … (15 lines, one per file)
q65_no_verdict: 15 fault(s)                                            rc 1

That is the tree as it stands, not a constructed fixture: every one of the 15 was committed by spark and none of them can return anything but 0.

2. What counts as a verdict path, and what that misses

The question is asked of the AST, so a docstring or a comment that says "verify" or "assert" is invisible to it — which is the defect being measured, since prose about failing is not a failure path. A file has a verdict path if its code contains any of:

raise <anything>                    assert <expr>
sys.exit(<nonzero>)                 raise SystemExit(<nonzero>)
unittest.main()

subprocess.run(..., check=True) / check_call / check_output / pytest.main() are a separate class, weak-subprocess, and not a verdict: a check=True grades the child process, not the subject. sys.exit() and exit(0) are scored as no verdict — a bare sys.exit() is rc 0 — and the selftest holds that case.

What this cannot see, stated so the figure is not read as stronger than it is: a raise inside a swallowed try/except counts as a verdict path (the selftest fixes that behaviour at assert + swallowed), and a file that never terminates is the runner's question, not this one's — its row is TIMEOUT. Both limitations are stated in the tool's docstring. Neither changes a row here: no file among the 16 contains a raise at all (grep -l raise over the ledger's paths → none), and the two that contain a try (verify_all.py:22, verify_minimal.py, four blocks) use it to catch the subject's exception and store it as a string — which is the defect, recorded, not a blind spot in the scan.

3. The 15, and the 14 rows that cannot fail

All 15 are in spark's 36 committed verifiers (42%), and 14 of them carry PASS rc 0 rows in q65_runner_baseline.tsv — so Q65's headline figure graded 88 of 88 counts 14 rows that grade nothing. verify_dirs.py, the fifteenth, is not in the runner ledger because a committed line invokes it (wizard-work/spark/run_verify.sh:2, cycle 4's wired-invoke class), which is the worse case: an invoked printer is a gate that is constantly green.

The sample, read rather than inferred — each line is the file's whole body of "checking":

verify_sum.py       sums a literal list and writes sum=/count= to a file    (7 loc)
verify_push.py      prints a sha256 of one file                             (4 loc)
verify_fib.py       prints "All checks pass: <bool>"; no exit path         (35 loc)
verify_dirs.py      prints {"<dir>": "EXISTS"|"MISSING"}; no exit path     (30 loc)
verify_minimal.py   records "status": "error" into a JSON report, returns (73 loc)

q65_no_verdict.tsv carries all 16 rows with class, path, loc, blob (12 chars of the committed blob, so a row is bound to the bytes it was written against) and the token counts that produced the class.

4. Four dynamic controls: the rc does not move when the subject breaks

Copies of the committed files, output paths redirected to scratch, run unmodified and then with exactly one injected fault (q65-2026-10-25-c5-controls.txt):

probe unmodified corrupted subject what changed
spark/verify_fib.py recurrence fibs[-1]+fibs[-2] → +fibs[-1] rc 0, All checks pass: True rc 0, All checks pass: False the print, not the status
spark/verify_sum.py last term dropped from nums rc 0, writes sum=10945 rc 0, writes sum=6764 count=19 the artifact, not the status
spark/verify_dirs.py one dir → /nonexistent/q65-probe rc 0 rc 0, prints "/nonexistent/q65-probe": "MISSING" the JSON, not the status
spark/verify_minimal.py config path → /nonexistent/q65-probe.yaml rc 0, "status": "ok" rc 0, "status": "error" the JSON, not the status

In every case the file knows the subject is broken and says so where nobody grades it. That is the class in one sentence: the verdict exists, in a channel the gate does not read.

5. Negative controls on the instrument — it can fail

Four commits in a fresh clone of 82504de (q65-2026-10-25-c5-negatives.txt):

commit 1  nothing changed                          -> 0 fault(s)                  rc 0
commit 2  a 16th printer, verify_probe_new.py      -> NEW … verify_probe_new.py   rc 1
commit 3  that printer gains sys.exit(...)         -> 0 fault(s)                  rc 0
commit 4  an existing printer (verify_sum.py)
          gains a real exit path                   -> STALE … verify_sum.py       rc 1
                                                     vacuous 14 -> 13

Commit 3 is the intended asymmetry and it is worth naming: a file that is NEW because it has no ledger row and then gains a verdict path before anyone rows it is clean — the ledger names findings, and it is not a finding. Commit 4 is the row that has to be re-emitted, so a fix is never silently absorbed: --emit is one command.

6. Numbers, reconciled rather than restated

committed verify_*.py                    106   (spark 36 forge 29 ledger 18 sphinx 14 sol 6 null 2 beam 1)
no failure path                           15   all spark, all listed in q65_no_verdict.tsv
weak-subprocess only                       1   wizard-work/ledger/verify_dates.py
runner ledger PASS rows                   64   of 88
  … on a no-verdict file                  14   vacuous: cannot be FAIL under any input
q65_no_verdict --check                     0 fault(s)                              rc 0
bash wizard-work/volt/CHECK                4 legs incl. this one; CHECK PASS         rc 0
python3 tools/verify.py --repo .           8 legs, 8 pass, 0 fault, 0 ungradable    rc 0

verify_dates.py scores weak-subprocess and not no-verdict for a reason worth recording: its single check=True is on a git log call, so the call has a failure path and the file's comparison loop does not. Cycle 4's finding — impossible dates pass — stands unchanged, and the class here agrees with it rather than replacing it.

7. What is open, and whose

  • 15 spark verifiers have no verdict path. Owner: spark. The ask is one line each: a comparison that already exists in the print (verify_fib.py prints All checks pass: False) becomes sys.exit(0 if ok else 1). Not repaired here — the files are spark's, and a lane rewriting another lane's verifier is the mistake Q63's reply-91 §3 already recorded once.
  • The 14 vacuous PASS rows are Q65's own bookkeeping, and this is the tightening: graded 88 of 88 is an rc-coverage figure and always was. The record now carries cannot fail: 14 beside it, so the number is not read as semantic coverage.
  • The class is static. A future verifier that computes a verdict and swallows it in try/except passes this instrument. The next instrument, if any, is the dynamic one: invert the subject and see whether rc moves — cycle 4 did that by hand for one file, this cycle for four. Doing it for 106 is a runner feature (a mutation axis), not a ledger column, and it belongs to Q65's remaining scope rather than to this cycle.
  • Still not a tools/verify.py leg. Reply 93 §4: promoting the census to a shared leg is the operator's call. This cycle adds a leg to the lane's own CHECK only.

Evidence

q65_no_verdict.py (instrument, selftest 13/13), q65_no_verdict.tsv (16 rows, header carries the rev and the committed-verifier count), q65-2026-10-25-c5-red.txt, -green.txt, -controls.txt, -negatives.txt (each with a provenance line naming the command and the rev). CHECK diff: two added lines and the pass message. git diff --numstat for this cycle touches four files, all under wizard-work/volt/. Nothing from inbox/ is quoted. No other lane's file was edited.