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)
This commit is contained in:
1 parent
363c608555
commit
d4e5668897
2 files changed
+168
-19
No files matched your search
@@ -1,28 +1,76 @@
|
|||||||
#!/usr/bin/env python3
|
#!/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 subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
# Test file with known content
|
HERE = Path(__file__).resolve().parent
|
||||||
# File: "Hello world\nThis is a test file\nWith three lines total\nLast line here"
|
COUNTER = HERE / "lwc_counter.py"
|
||||||
# Actually the existing test_input.txt has different content
|
INPUT = HERE / "test_input.txt"
|
||||||
|
|
||||||
result = subprocess.run(
|
# The tracked fixture, byte for byte: "The quick brown fox ... and clever."
|
||||||
["python3", "/root/troupe-standup/wizard-work/spark/lwc_counter.py",
|
EXPECTED_SHA256 = "3127d0f89b3e87760130ee60e68eb9d9bf213ee83019062119361f1529cfd777"
|
||||||
"/root/.hermes/wizard-outputs/spark/test_input.txt"],
|
EXPECTED_STDOUT = "Lines: 1\nWords: 24\nChars: 125"
|
||||||
capture_output=True, text=True
|
|
||||||
|
|
||||||
|
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()}",
|
||||||
)
|
)
|
||||||
|
|
||||||
output = result.stdout.strip()
|
digest = hashlib.sha256(INPUT.read_bytes()).hexdigest()
|
||||||
lines = "Lines: 1" in output
|
_check(
|
||||||
words = "Words: 24" in output
|
digest == EXPECTED_SHA256,
|
||||||
chars = "Chars: 125" in output
|
f"fixture {INPUT.name} changed: sha256 {digest}, pinned {EXPECTED_SHA256}",
|
||||||
|
)
|
||||||
|
|
||||||
if lines and words and chars:
|
result = subprocess.run(
|
||||||
print("PASS: All counts verified correct")
|
[sys.executable, str(COUNTER), str(INPUT)],
|
||||||
sys.exit(0)
|
capture_output=True,
|
||||||
else:
|
text=True,
|
||||||
print(f"FAIL: Expected Lines: 1, Words: 24, Chars: 125")
|
)
|
||||||
print(f"Got: {output}")
|
_check(
|
||||||
sys.exit(1)
|
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())
|
||||||
@@ -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 / <name>`. 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.
|
||||||
Reference in new issue
Block a user