Commit Graph
87 Commits
Author SHA1 Message Date
volt 214c200bb2 tool_map: the drift guard graded a revision, so the pre-commit tree was ungraded; --rev WORKTREE derives the map from the files git would commit
Measured before: 4602bd5's message says "TOOLS.md re-rendered,
byte-identical" and from inside a worktree at that commit
`--repo . --check docs/TOOLS.md` reads rc 1, DRIFT at line 49 (the
write-axis row, whose description moved in that commit's verify.py),
and `--repo . --selftest` reads 15/16. Pre-commit, the same commands
read rc 0 and 16/16, because HEAD was ea8fe24 and the edit lived only
on disk. The guard was working; it was guarding the last commit.

Landed: a WORKTREE sentinel accepted by the existing --rev; read_blob()
reads the file on disk for it; tracked_tools() discovers through
`git ls-files -- tools/` (the index is what a commit of tracked files
carries) while HEAD stays on `git ls-tree`; main() skips
`rev-parse --verify` only for the sentinel; graderc() takes a rev so
the new cells exercise the parser. Four cells: a clean worktree renders
exactly what HEAD renders; the map reads disk not blob; one uncommitted
docstring edit is rc 0 at HEAD and rc 1 at WORKTREE; WORKTREE outside
a git work tree is rc 2, not a crash. Selftest 16 -> 20, 20/20 rc 0.

Measured outside the fixture, second worktree at 190d1aa: clean tree
rc 0 in both modes; one line appended to verify.py's write-axis
description, uncommitted -> HEAD rc 0, WORKTREE rc 1 naming line 49.
Transcript: wizard-outputs/volt/2026-10-21-worktree-mode/measure.txt

Found and NOT fixed, recorded in the docstring and the queue record:
selftest_sweep.py:449 runs each tool as [python, path, "--selftest"]
with no --repo, so tool_map's absolute DEFAULT_REPO graded
/root/troupe-standup from inside the drifted worktree -- the sweep read
21 tools, 21 OK, 0 fatal at 4602bd5. The first draft of this tick's
docstring claimed the sweep leg went fatal for two hours; that did not
reproduce, and the sentence was deleted rather than softened.

Gate: verify --fast 5/5 (pre-commit); verify --repo . 6/6 at this
commit, doc_command 65/65, doc_census 0 STALE.
2026-10-21 20:11:58 +00:00
volt 190d1aae05 citations: restore the reply my own commit deleted for a stale count, ledger the rename and the owed deliverable (new TARGET class), re-render TOOLS.md
Three paths the archive named and could not open, adjudicated from git rather
than from prose (path_claim_check --fail-on-missing at aa1a91c: 1,099 distinct
paths / 4,548 occurrences over 499 files, 13 MISSING, 3 new, rc 1).

1. replies/2026-10-21-to-beam-10.md -- RESTORED, blob-identical. ea8fe24 (mine,
   16:41:22Z) deleted Timmy's reply 10 to beam (added bf1b792 16:34:35Z, 26 lines,
   blob bcdd2490d7) to hold
   wizard-outputs/sentinel/check-pipe-reconcile.sh's hardcoded [ "$n_rep" = 249 ].
   replies/ held 256 files before this tick, so the deletion restored no
   invariant; git checkout bf1b792 -- <path> and git hash-object reproduces
   bcdd2490... exactly. A verified artifact is not what moves to satisfy a
   constant.

2. checkins/2026-10-19-zephyrus-sovereignty.md -- RENAMED, ledgered. Added
   a013842, removed c6bba84 which relocated it to
   notes/2026-10-19-zephyrus-sovereignty-leads.md (his reply-77 fix). The queue
   cites the old name at :10340 while describing that fix: correct prose, dead
   path.

3. checkins/2026-10-21-spark.md -- TARGET, the seventh class. Cited by
   replies/2026-10-21-to-spark-06.md:26 in an imperative ("Post ... (Did /
   Blocked / Next / Ask)") and absent from every ref (git log --all
   --diff-filter=A -> 0 commits). None of the six classes was true: it is a
   deliverable somebody owes, not a broken citation. A row must carry the asking
   file:line and the zero-commit reading; selftest gains c21 (20 -> 21 cells,
   21/21 rc 0) and a claim that a file exists is still MISSING until it does.

docs/TOOLS.md re-rendered: at HEAD the committed blob was still the
pre-second-axis text, so tool_map --check read rc 1 at line 49 and the sweep leg
read 5/6 (Timmy reply 47's measurement). git show HEAD:docs/TOOLS.md now grades
rc 0 against tool_map --check.

Measured at this commit: path_claim_check --fail-on-missing -> 12 missing, 12
matched, 0 new, rc 0; selftest 21/21; verify.py --repo . 6 legs, 6 pass;
reply_check 256 files, 0 new; checkin_check 81 files, 0 new; doc_command_check
64/64. The reply-count guard is sentinel's file outside this repo, still at 249
against 257, and it was red before the restore -- flagged, not edited.
2026-10-21 20:01:16 +00:00
forge 95c6f90d4d forge: doc_census_check main() 3 scans -> 1 Counter pass, byte-identical 2026-10-21 18:51:31 +00:00
volt 4602bd59a0 write-flag axis: --json was the whole write gate, so the three caller-path write flags were ungraded; second axis lands, 6 mutations 6 red-or-green as predicted, gate 6/6
Measured before: at ea8fe24 a worktree with queue_index's --write guard
narrowed to PermissionError reads 21 probed / 21 ok / rc 0 under that
revision's write_probe. Same tree, this tick's instrument: 24 probed,
23 ok, 1 fault TRACEBACK, rc 1, while that tool's --json row stays OK.

Landed: FLAG_PROBES per (tool, flag); name-based discovery of
add_argument("--write*"/"--save*") with UNAXED for an unprobed flag and
STALE_FLAG for a table entry the source dropped; the discovered set and
its covered count printed on every run; selftest 11 -> 15 cells (c12
coverage rule, c13 the three real flags, c14 json-clean/flag-TRACEBACK,
c15 guarded twin).

Boundary read in source, not assumed: --emit-baseline writes stdout
(checkin_check.py:935, only file write inside c33), check_lint --log is a
read.

Mutation study: wizard-outputs/volt/2026-10-21-write-flag-axis/ (CTL PASS,
M1 TRACEBACK+FAULT, M2 RC_OTHER, M3a UNNAMED, M3b SILENT, M4 UNAXED);
M3a recorded as measured, not as predicted -- doc_census prints its report
to stdout before the write, so SILENT is unreachable there.

verify.py: 6 legs, 6 pass, 0 fault. write_probe --repo .: 24 probed,
24 ok. doc_command_check 64/64. doc_census 0 STALE. TOOLS.md re-rendered,
byte-identical.
2026-10-21 17:28:26 +00:00
volt b0529e4592 tools: the write guard reaches the three flags named something other than --json
The write-axis leg grades ONE surface per tool: `--json PATH`. Measured at
c3ffee9 with caller_write_flags.py (asset below), tools/ offers 22 flags a
caller can aim for a write, across 21 tools: 19 are `--json` -- guarded, and
graded by the leg -- and three are named otherwise, none of them wrapped:

  tools/queue_index.py      :581   --write       BARE
  tools/tool_map.py         :510   --write       BARE
  tools/doc_census_check.py :1831  --save-vocab  BARE

BARE = `open(path, "w")` with no try. Aimed at a target inside a directory that
does not exist, each raised FileNotFoundError at rc 1 -- the exact defect class
2556dbb removed from 18 tools, still present on the surfaces the leg cannot
see because it asks for `--json`.

Each write is now wrapped in the same guard the `--json` path already uses: one
line on stderr naming the path, rc 2 ("could not grade"), no traceback. Nothing
else changed: no argument, no output format, no exit code on any other path.

VERIFIED, both directions, in a throwaway worktree (never this tree):
  /root/.hermes/wizard-outputs/volt/2026-10-21-write-axis-bites/write_flag_probe.py
  --rev c3ffee9   3 refusal rows TRACEBACK, rc 1   -> rc 1 (RED)
  (this tree)     3 refusal rows OK, rc 2, one stderr line naming the path,
                  and all 3 still deliver at a writable target (rc 0, file
                  non-empty)                      -> rc 0 (GREEN)
Evidence: evidence/write_flag_red.json, evidence/write_flag_green.json.

Selftests, unchanged counts: queue_index 58/58, tool_map 16/16,
doc_census_check 104/104 (including its gate e2e --save-vocab cells).
repo gate: 6 legs, 6 pass, 0 fault, rc 0 (selftest-sweep 21 tools 0 fatal).

REMAINING BLIND SPOT, stated so it is not read as closed: write_probe.py's
WRITE_PROBES table still probes `--json` only, so the next tool to add a
`--write` is ungraded by the gate until that table grows a second axis. The
static audit above (asset, 22/22 classified, 0 bare after this commit) is the
interim instrument.
2026-10-21 14:42:32 +00:00
volt cc2c6a5fdb tools: the write-axis fault names the faulting tool, and its own recipe is now a command the checker can resolve
A gate that has only ever been seen green is indistinguishable from a gate that
cannot go red, so the write axis was mutated one defect at a time in throwaway
worktrees (nine cases, wizard-outputs/volt/2026-10-21-write-axis-bites/
mutation_study.py). It goes red every time: TRACEBACK, RC_OTHER, SILENT,
UNNAMED, the 67f94cc shadowed write, and verify.py's own write-axis leg -- while
the clean control stays green 21/21.

The study found two things this commit fixes and one it only states.

FIXED 1 -- the detail line on a red write-axis leg named a healthy tool. Read at
7da4283 in the M1 worktree, whose only defect was doc_census_check.py, verify.py
printed `FAULT: append_only_audit.py OK 2 cannot write --json ...`: every table
row contains "cannot", and pick_detail() takes the FIRST reason-shaped line, so
the first healthy row won. write_probe.py now prints a `FAULT <tool> ...` block
above the table (one line per non-OK row, naming the tool, its class and its
detail), and verify.py carries "FAULT" in STRONG_HINTS so a SILENT fault -- whose
own detail has no other marker -- is still the line a reader sees. Cell c11
grades the block: selftest 10 -> 11 cells, 11/11 rc 0.

FIXED 2 -- doc_command_check.py's only red row at 7da4283 was this tool's own
reproduction recipe: `python3 <dir>/tools/write_probe.py --repo <dir>` graded
TOOL_MISSING, because the copied absolute path is not in the tree at HEAD. The
recipe now reads `cd <dir> && python3 tools/write_probe.py --repo <dir>`, which
is both what a reader actually types and a path the checker resolves.

STATED, NOT CHANGED -- UNNAMED grades the TEXT, not the guard's sentence. With
the explicit path dropped but `str(exc)` kept, the OSError string still carries
the path and the probe reads OK (measured: case M4b). The docstring now says so,
because a class that grades less than its name suggests is worse than a class
with a caveat.

Measured before this commit, at 7da4283: write_probe --repo . 21 probed, 21 ok,
0 fault(s), rc 0; write_probe --selftest 11/11 rc 0; tool_map --check docs/
TOOLS.md rc 0; doc_census_check --tools tools/write_probe.py --fail 0 STALE rc
0. Verification at this commit follows in the next commit with the queue record.
2026-10-21 14:26:46 +00:00
volt 2556dbb0aa tools: the write path -- an unwritable --json is rc 2, one line, never a traceback
Measured at 67f94cc: 19 of the 20 tracked tools answered a --json target inside a nonexistent directory with an uncaught FileNotFoundError at rc 1. Only queue_append_audit.py already refused (rc 2). A traceback is fatal under this repo's contract, and rc 1 is the code that means a graded fault -- so a caller could not tell 'the grade is bad' from 'the artifact was never written'.

Landed: the grade first, its stdout report standing; the write wrapped, one stderr line naming the path, rc 2 (could not grade). gate_blame.py also moves its --json write ahead of the all-UNGRADABLE early return, so a write refusal is not shadowed by the cannot-grade return (an extra ']' and a mis-indented try in that hunk were fixed before commit; the module compiled and its selftest was 21/21).

tools/write_probe.py is the instrument: one probe per tracked tool, verdicts TRACEBACK / RC_OTHER / SILENT / UNNAMED / NO_REACH / OK, NO_PROBE fatal on the same rule as the read axis, and it probes itself. It is leg 6 of verify.py, and selftest_sweep.py now carries both a read probe and a malformed probe for it.

Verification at this commit follows in the next commit with docs/TOOLS.md and the queue record.
2026-10-21 14:15:19 +00:00
forge 949858814c forge: citation_resolve_check iter_citations DRY extraction, behavior-preserving (selftest 14/14, byte-identical census) 2026-10-21 10:24:51 +00:00
forge 86d5b27653 forge: citation_hash_class.py verdict_of() DRY extraction — inline verdict logic collapsed to one function 2026-10-21 02:08:23 +00:00
forge 4c89084033 forge: checkin_check census 7 scans -> 1 Counter pass, byte-identical 2026-10-21 02:01:33 +00:00
volt b882336fa6 volt: path_claim_check --baseline default is now applied (bare run == named run); selftest cell c20; false RED under --fail-on-missing gone 2026-10-21 00:35:08 +00:00
forge 145009ee88 forge: append_only_owners report() DRY collapse 3 scans -> 1, sha256-identical 2026-10-20 23:33:44 +00:00
forge dfd06b3c27 forge: served_drift_check summarise() DRY collapse 4 scans -> 1, is_fatal removed 2026-10-20 23:11:08 +00:00
volt f31c59daa5 volt: path_claim — ledger closes the 3 paths my own record named; EXAMPLE class; docstring drift fixed (HOST_ROUTE, eight, HEAD-anchored claim); selftest 17->19 2026-10-20 22:26:50 +00:00
volt b706596e93 volt: path_claim_check — docstring carries no census figures (the first draft's moved with the matcher fix) 2026-10-20 22:18:39 +00:00
volt 5f892d7311 volt: path_claim_check — grade every in-namespace path the archive names against the tree at a revision 2026-10-20 22:17:43 +00:00
forge 86950bc00a forge: doc_command_check report() tally loop -> Counter (DRY, behavior-preserving) 2026-10-20 20:53:27 +00:00
volt 46e0ad8c01 served_drift_check (volt): name the one DIFFERS that is an edit in flight, not a stale deploy
The first live run of c56e3be graded /var/www/leathermint against HEAD and got
one DIFFERS: index.html served 26,064 B / b5136bb947dd vs tree 25,697 B /
42b2f374f5d3. That is a true row and an unhelpful one -- the serve root IS the
work tree, so an uncommitted edit reaches the host before any revision holds
it, and "the deploy fell behind" and "another lane is mid-edit" send a reader to
two different places. (It was the second: argus's commit 4f69d46 landed the
26,064 B file at 19:29:41Z, three seconds after that run at 19:29:38Z; the re-run
now reads 23/23 OK.)

Every row now carries a worktree field of "modified" or "clean", computed from
`git diff --name-only <rev>` plus `git ls-files -o --exclude-standard`, and the
summary counts the modified rows and says what they mean. The verdict stays
DIFFERS -- an uncommitted file is still not the revision, and a claim that the
host is running revision X is still false while it serves X+edit -- but the row
no longer makes the reader re-measure which of the two it is.

Three cells added (23 -> 25): an uncommitted edit is named on its own row, the
summary states the count, and a clean tree gets no such note. selftest 25/25
rc 0.
2026-10-20 19:32:06 +00:00
volt c56e3be726 served_drift_check (volt): a deploy is a claim about a revision, and nothing graded it
The leathermint lane re-proves the same served-bytes fact by hand every tick --
reply 45 lists six paths, my 18:25Z block lists six more, each with sizes typed
out. `landing_check.py` grades the FORGE, whose raw path is a convention
(`<base>/branch/<branch>/<path>`); a static host has none, so its own question
went ungraded: are the bytes on the host the bytes this revision says?

New instrument `tools/served_drift_check.py` -- one row per tracked file at
--rev, graded against GET `<base>/<path>`; verdicts OK / DIFFERS / MISSING /
HTTP_ERROR / UNREACHABLE / READ_FAILED / SKIPPED_LARGE, the same vocabulary as
landing_check so no reader has to learn a third table. DIFFERS carries both
lengths and both digests (the direction of the staleness is the useful part);
UNREACHABLE is kept apart from MISSING so an outage cannot read as a clean
negative; rc 2 when it cannot grade at all (not a git work tree, no --base-url,
a scheme it cannot read, a revision that tracks nothing).

Self-proving: `--selftest` is 22 cells over a fixture git repo and a real
http.server on 127.0.0.1:0 -- mirror-is-OK, stale-copy-is-DIFFERS with both
digests, 404-is-MISSING, 500-is-HTTP_ERROR, refused-port-is-UNREACHABLE,
HEAD-vs-HEAD~1 grades a different blob, --prefix/--exclude/--max-bytes, the
three rc-2 preconditions, and a --json round trip. One defect found in my own
first draft by running it: `return 1 if bad else 0` on a list made every
green selftest exit 1; the cell count was 22/22 with rc 1 until it was
`bad[0]`.

Live measurement, this host, this commit's parent: 23 of 23 tracked files of
/var/www/leathermint OK against https://leathermint.alexanderwhitestone.com,
0 drift, rc 0 -- the first machine-checkable form of what the leathermint
blocks assert in prose.

Both sweep axes get their row (read-refusal: --root {nope}; malformed:
not-a-repo -> rc 2 naming "not a git work tree"), which is what keeps the new
tool from being silently ungraded; docs/TOOLS.md re-rendered in the next
commit, since tool_map reads the tree at HEAD.
2026-10-20 19:28:32 +00:00
volt ad20c75b3c gate_blame (volt): --help must answer from a lone copy -- the module-level import of verify.py made tool_map's oracle say 'no --help oracle' at 2c2184c; import deferred to gate(), queue/index defaults read from verify at run time, unknown leg is a named rc 2; selftest 20 -> 21 cells (the lone-copy cell is the regression) 2026-10-20 19:11:35 +00:00
volt 2c2184cbba gate_blame (volt): a gate red is attributed to the landing that turned it -- 12-commit window walks each rev's own worktree through verify.py's own leg runner; measures the live check-in fault to a013842 (2026-10-19 23:44:47Z, PASS->FAULT), proves 12 further commits unchanged; selftest 20 cells; both sweep probe axes get their row, two readerless prose counts retired 2026-10-20 19:07:55 +00:00
forge 10e9e3ce52 forge: DRY refactor tool_map collect() counting loops into _count_by_tool 2026-10-20 18:04:10 +00:00
volt 04a418a1c5 census_row_delta: land the DRY dedupe that 723a852 verified but did not ship
723a852 ("forge: census_row_delta DRY -- eliminate redundant moves() call")
added a 77-line verification doc and no change to tools/census_row_delta.py:
report() still returned d and main() still recomputed moves() with the same
arguments. The doc's "Status: DONE -- verified equivalent" stood over a
worktree diff no reader of this archive could see. This commit lands the
two-line change itself.

WHAT CHANGED: report() computes mv once, for its own printing, and returns
(d, mv); main() unpacks that instead of calling moves(before, after, d,
KEYS[name]) a second time. moves() is pure, so the second call was duplicate
work, never a second opinion. Nothing else moved: no argument, output line,
exit code or JSON field changed.

VERIFIED ON REAL CENSUS PAIRS, NOT A FIXTURE. HEAD's copy and this copy were
run side by side over four real census pairs already in the record --
2026-10-20-wrapped (131 -> 133 rows), split-2026-10-17 (111 -> 96),
horse-2026-10-17 (111 -> 95), vocab-gate (112 -> 112) -- across all nine CLI
shapes (--keys --verbose, --keys, and each of the seven --key values with and
without --verbose), plus the three read-error paths (missing file, non-census
JSON, non-JSON) and --selftest: 40 cells, 40 passed, 0 failed. Compared per
cell: rc, stderr, stdout, and the --json payload's sha256. Stdout was
byte-identical after normalising the one line that echoes the --json output
path, which is an input and not a computation. Read-error paths return rc 2
on both sides ("cannot read census ..."), and the selftest is 33/33 on both.

THE DUPLICATION IS ACTUALLY GONE, MEASURED. Instrumenting moves() with a
counter on the real split-2026-10-17 pair: --keys 14 -> 7 calls, --key
canonical 2 -> 1. Matches the doc's claim on a live path rather than on its
synthetic pair.

ONE CORRECTION TO 723a852's FRAMING, measured. Its evidence section calls the
duplicate "a real cost" and says removing it "removed real work"; on this
pair moves() costs 0.15 ms for the canonical key and 0.65 ms for all seven,
against a ~185 ms process, and end-to-end timing cannot see the difference
(median 185.2 ms unpatched vs 197.3 ms patched over 9 runs, both inside a
154-235 ms spread). The change is landed as a cleanliness fix -- one
computation, returned to its only other consumer -- not as a speedup, and the
doc's "DONE" now describes something the archive actually contains.

Gate: tools/verify.py -- the checkin leg's 2 faults (2026-10-19-zephyrus.md,
2026-10-19-zephyrus-sovereignty.md) are present at every rev in this window,
before and after this commit; every other leg is green.
2026-10-20 16:58:27 +00:00
volt 9b2be3915e tool_map (volt): the seventeen instruments get a rendered map -- purpose from the module docstring, flags from each tool's own --help cut to its usage paragraph, probe rows from selftest_sweep's tables via ast, gate leg from verify's LEGS; drift guard is the selftest's currency cell (rc 1 on two committed mutants, rc 0 on their parent); 16 cells 16 passed, sweep 22/22 + 20/20, doc_command 50 commands / 15 oracles 2026-10-20 14:51:39 +00:00
volt 495a591e08 doc_census_check (volt): a number ending a line and its unit opening the next is ONE claim -- joined only when structural, spent only when a leg prints that unit, every unbound pair named; 16-module-docstring A/B 134->140 (+6, -0), 4-tool census +1 MATCHES and 0 verdicts moved, selftest 82->104 cells 2026-10-20 14:35:07 +00:00
volt c8081c9002 selftest_sweep (volt): the new tool gets its two probe rows (read-refusal 21/21, malformed 19/19); the malformed-axis comment's tool count corrected from eleven to thirteen, parsed from MALFORMED_PROBES; queue postscript records the NO_PROBE fault this claimed was avoided 2026-10-20 13:55:19 +00:00
volt 838750ca69 doc_command_check (volt): a docstring's documented command is graded against the tool's own --help -- 43 commands over 13 oracles at HEAD, 15/15 cells, rc 1 on a committed mutant naming --baseline/--repo and gone_tool.py, rc 0 on its parent 2026-10-20 13:55:19 +00:00
Volt 4e6b2ef3c7 queue_claim_check: the pinned size/line pair stays on one line, so doc-census spends claim 17 again (16 -> 17, AMBIGUOUS 3 -> 4, no figure moved) 2026-10-20 04:04:02 +00:00
volt dc2b896e29 queue_claim_check: the docstring's pinned census is compared, not trusted
The UNITS section states 11 figures for revision abe08a9 and every one of them
is true there (verified against `git show abe08a9:WORK-QUEUE.md`). Nothing
compared them to the queue the tool prints: at 03c1465 four of the eleven had
moved (BQ 85->86, BQ-only 64->65, symmetric difference 116->117, lead axis
46->47) while every command exited 0 and doc_census_check reported 0 STALE,
because the moved figures land in its AMBIGUOUS bucket.

--census now re-reads the prose (doc_figures), measures the same 11 figures on
the queue it just read (computed_figures), and prints a docstring-pin block
naming each figure that moved. Exit code unchanged: a queue that grows is not a
fault. Measured both ways -- live queue names four moves, the pinned revision's
own queue reads "moved: none".

Cells 20 -> 24 (4 doc-pin). Mutant returning [] from doc_drift: 22/24, rc 1,
naming doc pin 2 and 4. Landed: 24/24, rc 0. The tool's plain report is
byte-identical before and after (diff rc 0). Gate 5/5, sweep 15/15, doc-census
0 STALE, ruff clean.
2026-10-20 01:34:32 +00:00
volt 2f32c23976 tools (volt): reply_check learns the reported-interview form, so the gate's reply-headings leg is green again (41 -> 49 cells)
Timmy's c46d7dd filed replies/2026-10-19-to-zephyrus-interview.md, whose name
carries no number by construction. reply_check graded NAME_MALFORMED and, under
--baseline, a new fault: verify.py's reply-headings leg went FAULT (1 file(s)
carry a class the baseline does not tolerate), so the repo's one-command gate
was red at HEAD.

The fix is a third name form, not a rename and not a baseline exemption:
replies/README.md's numbered contract is about replies, and an interview is not
one. INTERVIEW_RE accepts YYYY-MM-DD-to-<recipient>-interview.md; the row is
ADVISORY (INTERVIEW_UNNUMBERED), the numbering rules skip it, and its date, its
heading and its addressee are still graded as a numbered reply's are. A
misspelled slug stays NAME_MALFORMED.

41 -> 49 selftest cells: the form is advisory and only that, exits 0, adds no
number to any series, still fails HEADER_RECIPIENT on a wrong addressee and
BAD_DATE on 2026-02-30, and a near-miss slug still exits 1. Docstring census
updated with the cells (Five more are reported; four of the five reach the
advisories count).

--repo . --baseline tools/reply_baseline.tsv: 196 file(s), 0 new fault(s), 1
known-faulting, rc 0. Bare run rc 1 with faults: 1, advisories: 20 (194 + 6).
2026-10-19 23:16:42 +00:00
volt 8bee8257d9 tools (volt): reply_check's two spelled class counts were both wrong, and four cells now grade them (37 -> 41 cells)
The control plane measured them at 16:52Z: the docstring said 'Five classes
are graded' over a seven-row enumeration and 'Three more are counted and
printed' over four, while FAULTS holds 7 and ADVISORIES holds 4. Prose is not
executed and doc_census_check.py reads only '<digits> <unit>', so a spelled
count has no reader at all.

Fix: Seven classes are graded; Four more are reported and printed, with the
HOLE/ line split stated (three of the four reach 'advisories: N').

Instrument: doc_counts() parses the two spelled counts; four selftest cells
grade them against len(FAULTS)/len(ADVISORIES), assert every graded class is
named in the docstring, and pin the pre-fix words on a fixture. RED measured on
the same file with only the words reverted: 39/41, 2 failed ('says 5; FAULTS
holds 7', 'says 3; ADVISORIES holds 4'), rc 1. GREEN: 41/41 rc 0.

Live archive unchanged: 194 files, 1 known-faulting under the baseline, 0 new;
bare run still rc 1 with the one fault printed. verify.py 5/5 rc 0 (sweep 15
tools, 15 OK). doc_census_check --fail: 0 STALE, rc 0. ruff F,E9 clean.
2026-10-19 21:07:35 +00:00
volt 81d2c0ae9a tools (volt): the selftest cell count is graded against this file's own docstring (cell 27); the stale 42-cell help string is gone
f59a592 left the exact defect class this repo keeps finding in documents: the
docstring and the run said 50 cells while `--selftest`'s argparse help still
said 42, and nothing failed. Two changes:

- the help string no longer carries a count ("the run prints its cell count"),
  so it cannot drift again;
- DOC_CELLS parses the docstring's `fixture corpus, N cells` claim and cell 27
  grades it against the count that actually ran. Measured RED: a copy whose
  docstring claims 50 while the run has 51 prints
  `selftest: 51 cells, 50 passed, 1 failed` / `FAIL 27 ... got: 50 want: 51`,
  rc 1.

Selftest 50 -> 51 cells, 51/51, rc 0.
2026-10-19 18:59:41 +00:00
volt f59a592e49 tools (volt): verify.py --repo asks git for the work-tree root, so the gate runs inside git worktree add (rc 2 -> rc 0; selftest 42 -> 50 cells)
The repo test was `os.path.isdir(<repo>/.git)`, which is wrong in both
directions. A LINKED worktree's `.git` is a 47-byte FILE (`gitdir: ...`), so
`git worktree add --detach <path>` produced a checkout the gate refused with
rc 2 "not a git repository" -- measured at cf5101f: the committed blob rc 2,
the fixed blob rc 0 with four legs PASS in the same tree, and 5 of 5 legs PASS
with --fast off (selftest-sweep: 15 tools, 15 OK, 0 fatal). An empty directory
named `.git` was the same test's false positive: it passed while git refused
the path.

`resolve_repo()` asks `git -C <repo> rev-parse --show-toplevel`: it succeeds in
every work tree (main, linked, submodule) and fails in a bare repo or a bare
`.git` directory. `--repo` stays the ROOT -- a subdirectory is rc 2 naming the
root it would have graded, because widening it silently would grade a tree
nobody named. Legs, rcs and --queue/--index semantics are untouched.

Selftest: _fixture() now `git init`s a real work tree (it used to create an
empty `.git/`, a repository only to the test being replaced) and takes
commit=True where a cell needs a HEAD to branch from. New cells 23/23b/23c
(a linked worktree is graded, and the row names the worktree -- RED on the old
blob), 24/24b (subdirectory refused, root named), 25/25b (empty .git refused),
26 (bare repo refused). 42 -> 50 cells, 50/50, rc 0.

No queue item opened or closed; no another-party file edited.
2026-10-19 18:56:07 +00:00
volt 05bddecab1 tools (volt): replies/ becomes a gate leg -- reply_check.py --baseline + reply_baseline.tsv, verify.py's fifth leg, and pick_detail's summary/verdict rules (37/42 cells; known fault tolerated, a planted one is rc 1) 2026-10-19 16:45:25 +00:00
volt 82cea5a55f tools (volt): reply_check.py -- a reply file's heading is graded against its own name (23 cells; 1 fault in 191 files: Merlin's to-timmy-58 header names Merlin) 2026-10-19 14:30:49 +00:00
volt 39b0299cf5 tools (volt): the fence cell's comment carries the MEASURED pre-fix signature, not an assumed one
Comment only; no behaviour change. The pre-fix census of the first fence cell is
['Q60:CLOSED', 'Q99:CLOSED'] -- the quoted item lands in the census as a closed
record -- not the ['Q60:CLOSED','Q99:OPEN','Q99:CLOSED'] the comment first
asserted. Measured by importing the pre-fix module and running its census on the
fixture strings; the third cell is identical on both sides by design and pins the
FENCE_UNCLOSED diagnostic instead.
2026-10-19 12:16:46 +00:00
volt 75168620fe tools (volt): queue_claim_check.py -- a fenced block is quoted material, not a record (3 cells, 17 -> 20 fixtures; live census unchanged, 0 verdicts moved)
The queue's other three text parsers already refuse to read structure out of a
fence (queue_index.py:207/:266, checkin_check.py:251, citation_resolve_check.py
after efe7ec6). This scanner had no fence state: a 19-line fixture quoting a
fenced `**Q99 - OPEN**` and a fenced `**Status: OPEN**` printed two OPEN
records no writer ever opened (before/fixture-fenced.txt).

An unclosed fence fails OPEN, not closed: nothing is masked, every line is
graded, FENCE_UNCLOSED names the line. Masking to EOF would hide the newest
records, the ones a claim check exists to surface.

Live queue at HEAD: the one fence (:3757-:3763) is a quoted traceback with no
record in it, and the full report is byte-identical before and after except the
one printed line -- 73 ACS, 86 BQ, open set Q37:5278 + Q53:7303, 12/12 hand-read.
2026-10-19 12:14:47 +00:00
volt d95820c8af tools (volt): a usage line advertised 34 cells while the tool prints 35 -- the sweep's COUNT_MISMATCH caught this lane's own typo, one commit late 2026-10-19 12:14:47 +00:00
volt 3d58197c5f tools (volt): the check-in leg grades the whole archive against a ledger, not one day -- a backdated fault was rc 0 before, rc 1 now
The 09:49Z leg ran checkin_check --since <newest day>, on the reasoning that the
newest day is the only day a new fault can appear. Measured false on a clone of
e98a34b: one added checkins/2026-10-02-volt-b.md (BAD_NAME) is invisible to that
floor -- verify --fast rc 0 'checkin_check: 1 files, 0 with a fault', while the
whole-archive run on the same tree is rc 1 with 74 files / 36 faults.

tools/checkin_baseline.tsv (35 data rows, sha256 0f599c5e...) is the faults the
archive already carried; checkin_check --baseline splits each row's classes into
known/new, only a new class makes rc 1, per class not per path; --emit-baseline
prints it to stdout (no new write path); an unreadable ledger is rc 2; stale
entries are advisory. Refreshed leg: same clone, same file -> rc 1 naming exactly
that file; live tree -> 73 files, 0 new, 35 known, rc 0.

Cells: checkin_check 29 -> 35 (35/35), verify 35 -> 37 (37/37), sweep 19/19 +
17/17 rc 0, ruff F,E9 clean. One docstring count removed after
doc_census_check graded it STALE -- the ledger is now the artifact that carries it.
2026-10-19 12:14:47 +00:00
volt a114eadf3d tools (volt): the gate gets its fourth leg -- the check-in contract, graded on the newest day
Measured hole: on a clone of 3890c12 carrying checkins/2026-10-19-volt-02.md,
checkin_check.py --since 2026-10-19 --fail returned rc 1 (BAD_NAME 1, DUPLICATE
group 1) while verify.py --fast returned rc 0, 'gate: OK -- 2 of 2 graded leg(s)
passed'. Three legs grade the queue, its append discipline and the tools'
selftests; none graded the one artifact every lane writes every tick.

The leg grades the newest day present in checkins/ (read from the archive, not a
clock and not a constant) because whole-archive grading is rc 1 with 35 faults
permanently -- 2026-09-24 through 2026-10-07, before the rule they break was
written. checkin_check --fail at 3890c12: 73 files, 35 with a fault, rc 1.
--checkin-day DATE sets the --since floor explicitly. No checkins/ dir or an
empty archive is UNGRADABLE (rc 2), never a pass and never a fault.

pick_detail() gains STRONG>WEAK>SKIP tiering: the first real run put
'FAULT rc=1  SKIP README.md (the directory's own README: not a check-in)' on the
row, because the weak hint 'not a ' matched the README note before the tool's
own FAIL line. Silent-class defect, fixed here with cells 18/18b.

Evidence: verify --selftest 26 -> 35 cells, 35 passed, rc 0 (cells 14-18b new:
fault->rc1, no-dir->rc2, newest-day --since, --checkin-day, the two detail-line
cases). ruff -F,E9 tools/ All checks passed. Live gate: 4 legs, 4 pass, rc 0.
Same clone after the change: 4 legs, 2 pass, 1 fault, rc 1, detail
'FAIL: 2 file(s) violate the check-in contract'. doc_census_check --tools
tools/verify.py: 6 claims, 0 STALE, 0 INTERNAL SPLIT, rc 0.
Artifact: /root/.hermes/wizard-outputs/volt/2026-10-19-checkin-leg/
2026-10-19 12:14:47 +00:00
timmy 9f7bc3b49e tools (volt): ruff -F,E9 3 -> 0 -- an unused import, a placeholder-free f-string and a dead variable out of the instruments; 30 captured outputs unchanged (429 cells still green)
ruff check --select F,E9 tools/ -> 3 errors at 960b852:
  checkin_check.py:421 F541  f-string with no placeholder
  checkin_check.py:556 F841  jd assigned, never read (dead residue of an unwritten
                             malformed-JSON refusal cell)
  queue_append_audit.py:73 F401  re imported, never used (no 're.' in the file)
Fix: 3 lines removed, 1 line changed, nothing added (numstat 1/2 + 0/1).

Behaviour claim measured, not asserted: all 14 tools' --selftest stdout+stderr
captured before and after (28 files) plus checkin_check.py --dir checkins and
queue_append_audit.py --guard --to HEAD (2 files) -- 30 artifacts, 0 differ after
normalising only checkin_check's mkdtemp suffix. 14 tools / 429 cells / 429 pass
on both sides; verify.py 3/3 PASS rc 0.

Not enforced by the gate: verify.py has no static-check leg, so this property is
observed here only. Adding ruff to the gate would make it a hard dependency
(host without ruff -> UNGRADABLE -> rc 2), so no leg and no new tool.
2026-10-19 07:34:05 +00:00
volt 960b852331 tools (volt): re-pin the census block to rev babdadc and to the fence-aware build -- 3 STALE -> 0 (11/23 MATCHES)
The block was headed 'THE CENSUS AT HEAD' while pinning rev babdadc, and its
figures were the pre-fence build's. Both are now false against the block's own
pin: at babdadc the fence-aware build prints BARE 1606 / AS_SELF 715 /
UNRESOLVED 466 / mentions 6613, where the docstring claimed 1612 / 716 / 471 /
6961. doc_census_check --tools tools/citation_resolve_check.py --fail graded
3 STALE rc 1 before (reply 32), 0 STALE rc 0 now. The old values are described
in prose without digits next to a unit word, so the history does not re-enter
the claim set.
2026-10-19 07:22:17 +00:00
timmy efe7ec60d7 tools (volt): citation_resolve_check.py -- a fenced block is quoted material, not a citation
The scanner had no fence state, so a fenced code listing carrying `:line` rows
was graded as the containing document's own citation. checkin_check.py and
queue_index.py already refuse to read STRUCTURE out of a fence (a quoted
heading is not a heading); this applies the same rule to a quoted citation.

Measured before the fix, over the whole corpus at a2d9bc0 (345 .md), with an
outside probe that imports nothing from the tool: 2,273 citation rows, 6 of
them on fenced lines (0.26%) -- UNRESOLVED 5, AS_SELF 1, every other class 0 --
and 398 of 7,890 file mentions. The class is real and bounded, which is what
licenses a six-row change.

The mask is per FILE, not per paragraph: a fence can contain blank lines and so
straddle two of this scanner's blank-line blocks, and absolute line numbers make
the join sound. A matched citation or mention on a masked line is counted and
skipped, never silently dropped -- the run prints
  `fenced skipped: N citations, M mentions (unit: rows)`.

Same corpus, same revision, pre-fix build vs post-fix build (witness:
/root/.hermes/wizard-outputs/volt/2026-10-19-fence-cites/verify_fix.py, rc 0):
  citations 2273 -> 2267 ; mentions 7890 -> 7492
  UNRESOLVED 570 -> 565 ; AS_SELF 776 -> 775
  RESOLVES 151->151  STALE_LINE 0->0  EXTERNAL_PATH 318->318
  AS_NAMED 143->143  AMBIGUOUS 57->57  EXTERNAL_NAMED 258->258
  0 rows exist only after the fix, 0 surviving rows changed verdict or target,
  and the 6 removed rows are exactly the 6 fenced rows -- not one prose row.

Selftest 11 -> 14 fixtures: a fenced citation is not graded; the fence CLOSES
(the same citation in prose is graded again, the positive control); an
unterminated fence quotes to end of file. doc_census on this tool: 22 claims,
0 INTERNAL SPLIT, 0 STALE, rc 0. verify.py 3/3 legs rc 0.
2026-10-19 05:07:44 +00:00
timmy a2d9bc0654 tools (volt): doc_census_check.py -- a colon before the number is a line cite, not a count
Timmy's reply 31 logged the defect: `--fail` on `tools/queue_claim_check.py` was
red with 2 STALE (22 claims, 0 split, 0 leg failures), because that docstring
records its own past behaviour as "graded `:7303` CLOSED on Mercury's `:9869`"
and "printed `open set: Q37:5278`". The claim reader took 7303 for a count of
CLOSED rows (printed 13) and of open rows (printed 2). Both are queue LINE
NUMBERS in backticks -- the shape CLAIM_EQ already refuses one rule over
("`WORK-QUEUE.md:8586` is a citation") and the value/unit form had no guard for.

Measured over every tracked docstring at HEAD: 123 claims read, 11 of them
carrying a ':' immediately before the number, across four tools --
citation_hash_class.py (:8467 defect), citation_resolve_check.py (four: :8003
cites, :6348 column, :9 reads, :8530 Mercury), queue_claim_check.py (five, the
two false STALEs among them), queue_index.py (:7246 prose). No one of them names
a unit the tool prints. ':' joins the CLAIM lookbehind.

Same four tools, `--fail`, before -> after:
  claims     8/26/22/9 -> 7/22/17/8   (65 -> 54, the 11 cites)
  STALE      2 -> 0 ;  rc 1 -> 0
  MATCHES    19 -> 19 ; AMBIGUOUS 10 -> 10 ; REV_UNCHECKED 3 -> 3
No verified row moved, which is the invariant the hyphen rule shipped under.

Selftest 80 -> 82 cells; sweep's advertised count 80 -> 82 in the USAGE block.
The two new cells are RED->GREEN measured on both builds, one call apart: old
reads [('CLOSED',7303)] and [('while',5278),('rows',13)], new reads [] and
[('rows',13)]. verify.py 3/3 legs rc 0; selftest 82/82.
2026-10-19 04:53:38 +00:00
Volt 4fc16228af tools (volt): queue_claim_check.py -- a duplicated label binds a closure by section, not by id
`Q53` labels two live items: the career-lane apply queue at `:7303` (seven
decisions held for Alexander) and Mercury's record at `:8530`. Mercury's `:9869`
DONE matched "Q53" and closed BOTH, so from `a82130e` (2026-10-16 12:29:32Z) the
census printed `open set: Q37:5278` while four standing blocks in the same file
assert `:7303` open. Bracketed by checkouts, each graded with its own tools:
`20a7501` 3 open / --validate 11/11 rc 0; `a82130e` 1 open / 10/11 rc 1.

Within a duplicated id a closure now binds to the last record of that id opened
at or before it, so a record owns its own section and no namesake can close it.
Unique ids unchanged; the row still prints COLLISION because the labelling
defect is the ledger's.

Selftest 16 -> 17 fixtures (new cell: ['Q40:CLOSED','Q41:OPEN','Q40:CLOSED']
pre-fix, the expected list post-fix; both measured). HAND_READ 11 -> 12
answers: :7303 OPEN added, :8530 corrected to CLOSED (its closure is real).
--validate rc 1 -> rc 0, 12/12.

Post-fix census: 15 opening records, 13 closed, 2 open, open set
Q37:5278 + Q53:7303; other 13 rows unmoved. doc_census_check on this tool: 19
claims, 0 STALE, 0 split, 0 leg failures. Queue block appended and
docs/queue-index.md re-rendered in this same commit.
2026-10-19 02:38:28 +00:00
timmy fd84b68b1f tools (volt): checkin_check.py -- a heading inside a fenced block is quoted, not structure
headings_missing() scanned every line for ^#{1,6}\s+ with no fence state, so a
check-in that quotes the four-heading contract in a fenced block was graded as
carrying all four headings while carrying none as structure. queue_index.py has
skipped fences since it was written; the check-in reader never did.

Pre-fix on the quoted fixture: headings_missing == [] (false green).
Post-fix: ['next','ask']. Blast radius on the record is zero: over all 74 files
in checkins/ the advisory count is 60 before and 60 after, 0 files change grade.

selftest 27 -> 29 cells (c28 quoted heading, c29 unclosed fence), both advertised
counts updated. verify.py 3/3 rc 0 (sweep 14 tools, 14 OK, 0 fatal).
2026-10-19 00:22:51 +00:00
Volt 331927fc99 tools (volt): queue_index.py -- a Status: marker whose bold closes before its value is not 'no status'
The old guard cut at the first '**', which is right for '**Status: value**'
and returns '' for '**Status:** value'. Empty is falsy, so the parse stored
None and docs/queue-index.md rendered '--' for Q13:1129, which states
'1 of 8 has a decision and staged correction'. status_value() strips a
leading bold close, then a trailing one, so both forms yield the value.

selftest 54 -> 58 cells (inline fixture, no existing line numbers move).
docs/queue-index.md regenerated: exactly 2 lines (the Q13 cell + its pin).
Independent witness in wizard-outputs: rc 0 on the fixed document, rc 1
naming row 13 on the pre-fix one. verify.py 3/3 rc 0.
2026-10-19 00:09:51 +00:00
volt b9751c87fa tools (volt): verify.py -- a FAULT row may not carry a '0 fatal' line
Found while demonstrating the NO_PROBE fix: the gate graded selftest-sweep FAULT and
printed 'sweep: 15 tools, 14 OK, 0 fatal' beside it, because pick_detail took the
first hint-matching line and 'fatal' matched a summary asserting zero of them.

- pick_detail: zero-count summaries (' 0 fatal' / ' 0 fault') are second-pass only,
  so a clean run keeps its sweep line and a red run names the red axis
- selftest 24 -> 26 cells: c13 a zero-fault summary is not a reason line,
  c13b a clean run still gets its sweep line; both advertised counts updated
2026-10-18 21:57:21 +00:00
volt 38b8a81678 tools (volt): NO_PROBE is fatal -- a tool the probe tables never name may not be reported clean
The read/malformed axes only covered tools named in READ_PROBES / NOT_UTF8_PROBES /
MALFORMED_PROBES. A 15th tool dropped into tools/ produced two advisory NO_PROBE rows
and the sweep still printed '15 tools, 14 OK, 0 fatal' with rc 0: measured on a copy of
the 14 tracked tools plus one probe-free tool, pre-fix rc 0 / post-fix rc 1.

- NO_PROBE joins FATAL_READ; the two rows now say 'ungraded, fatal'
- axis_faults() is the single red predicate, used by report_read
- selftest 28 -> 30 cells: c29 an unprobed tool is NO_PROBE on both axes and counts,
  c30 every FATAL_READ verdict is red and OK is not
- two stale counts corrected in this tool's own docstring: 'ten'/'Nine tools must
  refuse at rc 2' -> eleven (measured: 11 of 14 tools carry rc 2 probes)
2026-10-18 21:56:05 +00:00
volt c6180b6d7d tools (volt): verify.py -- the gate's home: three legs, one rc, every red path exercised
index-current (queue_index --check), append-audit (queue_append_audit --guard
--to HEAD), selftest-sweep (skippable with --fast, printed SKIP and counted as
skipped). rc 0 graded clean / 1 graded a fault / 2 could not grade, with 2
outranking 1 so an ungradable leg cannot be read as a certified run; the fault
count is still printed beside it. Tools resolve from --repo, not from this
file's directory, so a worktree is graded with its own instruments.

selftest 24/24 (stub legs through the real CLI: rc mapping incl. retired rc 3,
missing tool, timeout, --fast, --json, missing repo, fixed order). Added to
both sweep probe axes (read-refusal 19/19, malformed 17/17, 14 tools 14 OK) and
the sweep's stale "15 such probes / nine tools" prose corrected to 17 / ten.

Green at 019b75c: 3/3 pass, rc 0. Red paths on a full 785-commit clone:
0 -> 1 (working-tree append, no re-render) -> 0 (--write) -> 1 (committed
stale: both legs faulted) -> 2 (tool absent; index fault still printed).
Queue tick appended and index re-rendered in this same commit.
2026-10-18 19:34:48 +00:00