test_shell_lone_copy_reds_on_its_sibling asserted the fixture path it had just
built while verify_hermes_setup.sh reports the path it resolved with readlink -f.
Under TMPDIR=/root/.hermes/profiles/volt/cache/scratch_link a correct pair read
MISSING and the gate went rc 1 (measured before the repair: that cell was the
only red, 15 others ok). The fixture root is now canonicalised once in setUp
with os.path.realpath; two new cells pin the alias reading instead of assuming
it -- a lone copy reached by a directory symlink names the real sibling that is
absent (rc 1), and the same alias with the sibling present reads PASS (rc 0).
CHECK-env-verifiers now runs the suite twice, ambient TMPDIR and a directory
alias it builds, so the shape that produced the flake is graded every run.
16 cells; negative control (raw mkdtemp restored in a scratch copy) reds the
alias leg and only that leg, rc 1.
snippet.py: check_tools() imports hermes_tools and requires callable(getattr(...));
--require is the negative-control hook; HERMES_HOME/HERMES_PROFILE/--home/--profile
resolve every path; rc 0/1/2. verify_hermes_setup.sh: HERE from $0, sibling
snippet.py graded, --home/--root/--profile, VERDICT line, rc 0/1/2.
New test_env_verifiers.py (14 black-box cells, stub hermes_tools on PYTHONPATH,
synthetic trees) and CHECK-env-verifiers. Pre-repair blobs: 9 cells red for
snippet.py, 6 for the shell script.
The old check imported json, subprocess and datetime -- all stdlib -- so
its failure condition was unreachable, and its version-reporting helper
check_package was defined and never called. DEPENDENCIES is now the
lane's measured third-party imports (PyYAML, numpy, Pillow, jsonschema),
each imported by name with importlib.metadata version; missing -> rc 1,
broken -> rc 1, usage error -> rc 2. email_validator is not declared:
spark's own email_validator.py is a local stdlib-only module.
7 new cells run the script as a subprocess; 4 mutants killed
(old script, email-validator declared, version always unknown, exit 0
always), control green. Queue Q120 closed with the record appended and
docs/queue-index.md re-rendered in the same commit.
A scan of wizard-work/spark for every remaining reference to the 25 paths
retired in a979e63 turns up six files, and each exists only to exercise or
describe one of them. They are retired here rather than repointed, because a
repointed cell would be a new test of the survivor wearing an old tool's name:
check.py imported count_words from word_counter.py through a
sys.path.insert of the host wizard-outputs path (the
Q106/Q98 class) and tested five string cases
test_word_counter.py the same five cases against word_counter.py
test_wordcount.py ran wordcount.py and compared to `wc -w`
verify_snippets.py the lane's "snippet verification", whose one check was
word_counter.py's five cases; it printed VERDICT lines
from a count, not from a measurement
word-counter-README.md documented word-counter.py's interface and a
7-word example, i.e. prose for a file that is gone
scratch_word_counter.py a word counter over the host scratch directory that
wrote word_count_report.json to a fixed host path
What replaces them: wizard-work/spark/test_line_counter.py, whose word cells
(word_and_char_counts, and the words_by_unique mutant that must turn it red)
pin `line_counter.py --words` on a fixture that is in the tree. check.py's and
test_word_counter.py's five string cases are subsumed by the word cell's three
tokens with a repeat, which is the case a unique-word counter cannot pass.
Not retired, and deliberately: word_count_report.json and the fixtures
test_words.txt / test-input.txt / test-empty.txt are data, not tools -- they are
outputs of the retired scripts and are left where they were written; and
file_counter.py, file-counter.py, count_functions.py, json_key_counter.py,
count_verified_skills.py, verify_count.py, passwd_lines.py and generate_stats.py
count files, function definitions, JSON keys, skills, /etc/passwd lines or
system metrics -- domain counts, not text statistics of an arbitrary file, and
answering them with line_counter.py would be a different tool. The boundary is
stated in the Q125 record.
Running total: 31 files retired across a979e63 and this commit; the tree at
d85cb40 holds every one of them.
line_counter.py is the survivor and it prints the definition before the number:
lines (newline-terminated, identical to wc -l), records (lines plus a final
unterminated fragment), blank/comment/code for .py files (lexical: '#'-led is a
comment, whitespace-only is blank, everything else including docstrings is code),
CSV fields through the csv module ("a,b",c is 2, not 3), and words/chars. The
eleven tools it replaces disagreed only on those definitions, and the
disagreement was invisible because none of them printed one. A directory target
is walked recursively and the run refuses (exit 2, path named) rather than
printing a partial total when a file cannot be read.
Retired, and where each behaviour went:
count_python.py file/line walk -> `line_counter.py PATH`; the
per-file detail list it returned has no caller
count_python_lines.py code/comment/blank breakdown -> PATH report
py_loc.py same breakdown, same key names
loc_counter.py same breakdown; its argparse surface goes with it
linecount_pycount.py totals -> lines/records keys, its code count -> `code`
code_stats.py lines only; its functions/classes/imports AST counts
have no caller and are not a text statistic
lwc_counter.py -> `--words` (lines, words, chars)
text_stats.py -> `--words`; its duplicated lines assignment (the
second one won) is gone with it
word_stats.py -> `--words`; unique/top-5 tables have no caller
file_stats.py -> `--words`
file_analyzer.py -> `--words`; its size_bytes is `wc -c`
quick_stats.py -> `--words`; bytes is `wc -c`; unique/top-5 retired
wordcount.py -> `--words` (its JSON envelope is not kept)
word_counter.py -> `--words`
word_counter_simple.py -> `--words`
word-counter.py -> `--words`
wordfreq.py -> `--words`; frequency table retired, no caller
word_freq.py -> `--words`; frequency table retired, no caller
Retired in the same commit because each graded a tool that no longer exists:
test_linecount.py, test_text_stats.py, verify_lines.py, verify_lwc.py,
verify_wordcount.py, verify_word_freq.sh, check_word_count_report.py
verify_line_counter.sh is repaired rather than deleted. It pinned
/root/.hermes/wizard-outputs/spark and "Total lines: 5587" -- a figure belonging
to the 65-line tool last held at 7359bce that 6b5197b had already replaced -- and
read rc 1 at the opening rev. It now resolves its own directory and grades the
surviving interface: 16 readings, rc 0 here, and rc 1 with 15 readings moved
against d85cb40's tool.
test_line_counter.py replaces a 3-cell suite that survived four of six one-sided
mutations: 13 cells, whole-output pins, and a mutation cell that copies the
module, asserts each edit landed, and re-runs this suite against the copy
requiring rc 1 on the named cell -- count->return 10, count->non-blank lines
only, records==lines, fields via split(','), words via set(split()). Five
mutants, five killed. Against d85cb40's tool the same suite reads 0/13, rc 1.
Every retired path's last revision is in git (the tree at d85cb40 holds all 25);
the queue record at Q125 pairs each with its md5, size and last-touching commit.
tools/path_claim_baseline.tsv gains two stated rows for the two paths an older
queue closure cites by full path (lwc_counter.py, verify_lwc.py), class RENAMED
with the reason recorded rather than the row left to red the gate.
Files: wizard-work/spark/line_counter.py, test_line_counter.py,
verify_line_counter.sh (repaired), README.md, VERIFICATION.md, 25 deletions,
tools/path_claim_baseline.tsv.
The eight test files Q98 leaves open (plus test_bfs.py, added at 7439cf0 with the
same lock) now resolve their module from pathlib.Path(__file__).resolve().parent
instead of /root/.hermes/wizard-outputs/<lane>.
tools/import_resolve_check.py --repo . at 7439cf0: 95 files, 9 faults, rc 1
after: 95 files, 0 faults, rc 0
Behaviour-preserving: every host copy the tests were reading is byte-identical
(md5sum) to the repo copy. Three absolute literals in spark/test_validator.py
that the static leg does not grade (load_json(...) argument strings at pre-fix
lines 12/16/25) are re-pointed too.
ledger/test_scratch_manifest.py was red before any edit (str ROOT vs
gen_manifest ROOT.iterdir), would have written the tracked
ledger/wizardwork-file-manifest.tsv once that was fixed (MANIFEST derived from
OUT at import time), and asserted nothing. It now re-points ROOT/OUT/MANIFEST,
guards MANIFEST inside a tempfile.mkdtemp(), and asserts the exact manifest row.
Non-vacuity: scratch/q98b/poison_probe.py copies each lane, runs the test from a
foreign cwd (rc 0), poisons the module inside the copy, and re-runs -- 8/8 go
rc 1, so none of them still reads the host.
Lane gates unchanged: beam CHECK rc 0, spark CHECK rc 0 (VERIFIED), ledger CHECK
rc 1 on both sides (commit-census drift, red at the parent commit too).
Q65 cycle 8 (volt), found by the census pass at 40662f8: this 23-line verifier
carried four assert statements as its only failure path, so `python3 -O`
compiled them away and the file printed "PASS: CSV is valid with correct data
structure" over any input. Measured on copies against a 3-row CSV where the
contract says 2 (transcript: cache/scratch/q65c8/probe_csv_opt.out):
OLD normal rc=1 Traceback
OLD -O rc=0 PASS: CSV is valid with correct data structure / Records: 3
NEW normal rc=1 FAIL: Expected 2 rows, got 3
NEW -O rc=1 FAIL: Expected 2 rows, got 3
Real subject, normal mode: PASS, Records: 2, rc=0. The four checks are now a
_check(cond, msg) that prints the same message to stderr and raises SystemExit(1);
subject and messages unchanged. Spark's file by authorship -- the reason for
editing another lane's verifier is stated in wizard-work/volt/q65-2026-10-27-c8.md
section 3 and in the queue addendum. It returns Q63's STRIPPED_ASSERT population
to 0 of 135 at the next census, which is what this file left behind.