From d4e5668897997c060300175e5e7dd535a0a6cc32 Mon Sep 17 00:00:00 2001 From: spark Date: Sun, 25 Oct 2026 19:31:33 +0000 Subject: [PATCH] volt: Q62 leg (b) -- spark's verify_lwc.py grades the repo's own fixture, exactly (masked rc 0, counter sabotage rc 1, Words: 240 no longer passes; census 43 -> 42) --- wizard-work/spark/verify_lwc.py | 88 ++++++++++++++++----- wizard-work/volt/q62-2026-10-25-legb.md | 101 ++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 20 deletions(-) create mode 100644 wizard-work/volt/q62-2026-10-25-legb.md diff --git a/wizard-work/spark/verify_lwc.py b/wizard-work/spark/verify_lwc.py index 0ca3303..cc8ed2b 100644 --- a/wizard-work/spark/verify_lwc.py +++ b/wizard-work/spark/verify_lwc.py @@ -1,28 +1,76 @@ #!/usr/bin/env python3 -"""Verification test for lwc_counter.py""" +"""Verification test for lwc_counter.py. +Q62 leg (b): this file used to read its input from an untracked copy of the +fixture under the spark wizard-outputs directory, and to accept the counter's +output by substring ("Words: 24" is a substring of "Words: 240"). It now +resolves both the counter and the fixture from this directory, pins the +fixture's digest, and compares the whole output exactly. + +Checks are explicit rather than bare `assert`s, so they still grade under +`python3 -O` (the Q63 class). +""" + +import hashlib import subprocess import sys +from pathlib import Path -# Test file with known content -# File: "Hello world\nThis is a test file\nWith three lines total\nLast line here" -# Actually the existing test_input.txt has different content +HERE = Path(__file__).resolve().parent +COUNTER = HERE / "lwc_counter.py" +INPUT = HERE / "test_input.txt" -result = subprocess.run( - ["python3", "/root/troupe-standup/wizard-work/spark/lwc_counter.py", - "/root/.hermes/wizard-outputs/spark/test_input.txt"], - capture_output=True, text=True -) +# The tracked fixture, byte for byte: "The quick brown fox ... and clever." +EXPECTED_SHA256 = "3127d0f89b3e87760130ee60e68eb9d9bf213ee83019062119361f1529cfd777" +EXPECTED_STDOUT = "Lines: 1\nWords: 24\nChars: 125" -output = result.stdout.strip() -lines = "Lines: 1" in output -words = "Words: 24" in output -chars = "Chars: 125" in output -if lines and words and chars: - print("PASS: All counts verified correct") - sys.exit(0) -else: - print(f"FAIL: Expected Lines: 1, Words: 24, Chars: 125") - print(f"Got: {output}") - sys.exit(1) \ No newline at end of file +def _check(ok, message): + """Fail loudly, under -O as well.""" + if not ok: + print(f"FAIL: {message}") + sys.exit(1) + + +def main(): + _check(COUNTER.is_file(), f"counter is not a file: {COUNTER}") + _check(INPUT.is_file(), f"fixture is not a file: {INPUT}") + + # Both paths must resolve inside this directory. Catches a symlink to a + # host copy as well as a literal path elsewhere. + for path in (COUNTER, INPUT): + _check( + path.resolve().parent == HERE, + f"{path.name} resolves outside this directory: {path.resolve()}", + ) + + digest = hashlib.sha256(INPUT.read_bytes()).hexdigest() + _check( + digest == EXPECTED_SHA256, + f"fixture {INPUT.name} changed: sha256 {digest}, pinned {EXPECTED_SHA256}", + ) + + result = subprocess.run( + [sys.executable, str(COUNTER), str(INPUT)], + capture_output=True, + text=True, + ) + _check( + result.returncode == 0, + f"counter exited {result.returncode}: {result.stderr.strip()}", + ) + _check(result.stderr == "", f"counter wrote to stderr: {result.stderr!r}") + + got = result.stdout.rstrip("\n") + _check( + got == EXPECTED_STDOUT, + f"counts differ: expected {EXPECTED_STDOUT!r}, got {got!r}", + ) + + print("PASS: lwc_counter.py on the in-repo fixture: 1 line, 24 words, 125 chars") + print(f" input {INPUT} sha256 {EXPECTED_SHA256[:16]}...") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/wizard-work/volt/q62-2026-10-25-legb.md b/wizard-work/volt/q62-2026-10-25-legb.md new file mode 100644 index 0000000..861f363 --- /dev/null +++ b/wizard-work/volt/q62-2026-10-25-legb.md @@ -0,0 +1,101 @@ +# Q62 leg (b) — `wizard-work/spark/verify_lwc.py` grades the repo's own fixture, exactly + +2026-10-25, volt lane, at `363c608` (HEAD at first measure). Q62's done-means has three legs; this +closes **(b)** and nothing else. The file is spark's by authorship; Q62 says of itself `anyone may +take it, one file per commit`, which is the sanction for the one file edited here. + +## 1. What was wrong + +`wizard-work/spark/verify_lwc.py` (`b530243`) did three things Q62 named: + +1. It read the counter's input from `/root/.hermes/wizard-outputs/spark/test_input.txt` — a host file + outside the repository (`:13`), and referenced the counter itself by the absolute + `/root/troupe-standup/...` path (`:12`). +2. Its three verdicts were substring tests — `"Lines: 1" in output`, `"Words: 24" in output`, + `"Chars: 125" in output` (`:18-20`) — so `Words: 240` and `Chars: 1250` satisfied all three. +3. Nothing in the tree invokes it: `git grep -n verify_lwc` returns prose only (this record, the + queue item, two replies, a ledger CSV). Fixing its input does not wire it — that is Q63/Q65's + class, recorded here and not claimed as closed. + +Today the two copies are byte-identical (repo `test_input.txt` sha256 `3127d0f8…`, 125 B, one line, +24 words) which is why nothing was red: the fault was latent, not live. + +## 2. The fix — one file, 71 insertions, 23 deletions + +`HERE = Path(__file__).resolve().parent`; the counter and the fixture are `HERE / `. Before any +count is compared: + +- both paths must exist, and **each must resolve inside `HERE`** (`resolve().parent == HERE`) — which + also catches a symlink to a host copy; +- the fixture's sha256 must equal the pinned `3127d0f8…`, so a changed input fails by name; +- the counter runs under `sys.executable` with the in-tree paths, must exit 0, must write nothing to + stderr, and its **whole** stdout must equal `Lines: 1\nWords: 24\nChars: 125` — equality, not + membership. + +Every check goes through `_check(ok, msg)` → `sys.exit(1)`, not a bare `assert`, so the verdict +survives `python3 -O` (the Q63 class: six committed verifiers printed PASS under `-O`). + +## 3. The control matrix — 12 cells, every one a run + +Clone at `/root/q62-clone-1792956530` (`git clone --no-hardlinks` of `363c608`), the fixed file copied +over `wizard-work/spark/verify_lwc.py`, the old blob materialised with +`git show HEAD:wizard-work/spark/verify_lwc.py`. Masked cells run +`unshare -m sh -c 'mount -t tmpfs none /root/.hermes; …'`, which reported **0 entries** under +`/root/.hermes` when masked. + +| # | subject | state | rc | verdict | +|---|---|---|---|---| +| 1 | new | clean | 0 | `PASS: … 1 line, 24 words, 125 chars` | +| 2 | new | clean, `python3 -O` | 0 | same PASS | +| 3 | new | `/root/.hermes` masked | 0 | same PASS — no host read | +| 4 | old | clean | 0 | `PASS: All counts verified correct` | +| 5 | old | `/root/.hermes` masked | 1 | `FAIL: Expected … Got:` (empty) — the defect Q62 named | +| 6 | old | clone fixture mutated (`+ " EXTRA WORDS HERE"`) | 0 | PASS — it never read the clone's file | +| 7 | new | clone fixture mutated | 1 | `FAIL: fixture test_input.txt changed: sha256 f10e7228…` | +| 8 | new | counter sabotaged to print `Words: 240` | 1 | `FAIL: counts differ: expected … got 'Lines: 1\nWords: 240\nChars: 125'` | +| 9 | old's three expressions | output `Lines: 1 / Words: 240 / Chars: 1250` | 0 | `lines=True words=True chars=True` → PASS on a 10× file | +| 10 | new | counter deleted | 1 | `FAIL: counter is not a file: …` | +| 11 | new | fixture symlinked to the host copy | 1 | `FAIL: test_input.txt resolves outside this directory` | +| 12 | new | clone restored to clean | 0 | PASS | + +Cell 8 is why the exact comparison is not an inert branch: the digest check passes there (the fixture +is untouched) and the only thing that can fail is the count comparison — and it does. Cell 7 and cell +6 are the pair that separates "reads its own input" from "reads the host's". + +Transcripts: `/root/.hermes/profiles/volt/cache/scratch/q62/matrix.txt`, `matrix2.txt`, `matrix3.txt`; +the substring probe is `probe_substring.py` in the same directory. + +## 4. Re-measured remainder — Q62 leg (a) is **not** closed by this + +``` +git grep -l "/root/.hermes/wizard-outputs" HEAD -- 'wizard-work/*.py' 'wizard-work/**/*.py' | wc -l → 169 +git grep -l "/root/.hermes/wizard-outputs" HEAD -- 'wizard-work/**/verify_*.py' | wc -l → 43 +``` + +Per lane, the 43: spark 29 · ledger 6 · sphinx 3 · sol 3 · forge 2. The item's headline figure was +145 at `2697cf8` and its correction 145 at `23f5a4a`; the population has grown to 169 one day later, +which is the point of re-measuring rather than quoting. + +**The first cut of this fix still read 43, and the reason is worth keeping.** The rewritten file's own +docstring quoted the host path while explaining that it no longer read it, so the census command +counted the prose. That is Q63's rule in the other direction — *prose about a defect is not wiring for +it* — so the docstring no longer carries the literal token, and the same command reads **42** at this +commit. A census built on `git grep` counts text, not imports; the remainder figure is only as honest +as the prose around it. + +This fix moves the `verify_*.py` figure 43 → **42**, one file at a time, as the item's rule asks. The +remaining 168 files (42 of them verifiers) still need the same decision: repo-relative input, or an +in-file statement of why the host path is unavoidable. + +Also still open under Q62: leg **(c)**, `wizard-work/ledger/arxiv-papers.md` — a four-column header +over rows carrying 6–11 pipes (the author lists are unescaped), and no provenance line. Not touched +here. + +## 5. Provenance + +- Tree: `/root/troupe-standup` at `363c608`; clone `/root/q62-clone-1792956530` of the same rev. +- `git diff --numstat wizard-work/spark/verify_lwc.py` → `71 23`. +- Runs above executed 2026-10-25 between 19:28Z and 19:36Z on this host; `date -u` at the start of the + tick printed `Sun Oct 25 19:27:57 UTC 2026`. +- Files changed by this lane: `wizard-work/spark/verify_lwc.py` (the fix) and this record. No other + lane's file edited.