#!/usr/bin/env python3 """q134_verify.py -- grade the retirement of `tools/inspect_tree.py`. WHY THIS EXISTS Q134: sol's `93fa377` committed an 8-line scoping script into `tools/`, the one directory where every tracked `.py` must be a graded instrument. Measured at `43af771`, that single file red the repo gate in two legs and two instruments' own selftests -- five rows from one 249-byte file: selftest_sweep `inspect_tree.py NO_SELFTEST_FLAG no "--selftest" in source` selftest_sweep `tool_map.py SELFTEST_FAILED 22/23 (docs/TOOLS.md drift)` selftest_sweep `write_probe.py SELFTEST_FAILED 14/15 (c7 table vs tree)` write_probe `FAULT inspect_tree.py NO_PROBE no write probe in the table` tool_map `FAIL HEAD: docs/TOOLS.md is the render of this tree` The repair retired the file out of the graded namespace and kept its bytes reachable: blob `3fea636f` at `93fa377`, sha256 `9e81ec9f`, copied to /root/.hermes/wizard-outputs/volt/2026-10-31-q134/inspect_tree.py.retired. A retirement that cannot be re-read is a deletion, so leg 1 grades the blob as well as the absence. WHAT IT GRADES -- three legs, each a reading rather than an assertion absence `tools/inspect_tree.py` is not in `git ls-tree HEAD tools/`, and blob `3fea636f` still resolves in this repository -- the file is retired, not lost. contract `tools/write_probe.py --selftest` in the graded tree exits 0. Its c7 is the cell that was red: the probe table must name every tracked tool under `tools/`, exactly. This is also the cheapest statement of the invariant the rogue file broke -- every `tools/*.py` is graded. mutant a clone of the graded tree with the retired blob written back and committed reads rc 1 from the same `--selftest`, with c7 naming `inspect_tree.py`. Without this leg the first two would be green on a tree where nothing can go red -- the class Q117 filed. The graded tree is only read. Legs 1 and 3 write inside a TemporaryDirectory. USAGE python3 wizard-work/volt/q134_verify.py [--repo DIR] [--verbose] EXIT 0 every leg as expected; 1 a graded fault; 2 could not grade (no git, no python3, or a --repo that is not a git worktree). """ import argparse import os import subprocess import sys import tempfile RETIRED = "tools/inspect_tree.py" BLOB = "3fea636fa5710d37b0f209321b0e62b5d3ccae15" BLOB_REV = "93fa377" DEFAULT_REPO = os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__)))) def git(repo, *args): p = subprocess.run(["git", "-C", repo] + list(args), capture_output=True, text=True, errors="replace") return p.returncode, (p.stdout or "").strip(), (p.stderr or "").strip() def run(argv, cwd=None, timeout=600): try: p = subprocess.run([sys.executable] + argv, cwd=cwd, capture_output=True, text=True, errors="replace", timeout=timeout) return p.returncode, p.stdout or "", p.stderr or "" except subprocess.TimeoutExpired: return None, "", "TIMEOUT after %ss" % timeout except OSError as exc: return None, "", "" % exc def leg_absence(repo): """Retired, not lost: absent from the tracked tree, blob still resolvable.""" rc, out, err = git(repo, "ls-tree", "-r", "--name-only", "HEAD", "tools/") if rc != 0: return "FAULT", "cannot list tools/ at HEAD: " + (err or "git rc %s" % rc) if RETIRED in out.splitlines(): return "FAULT", "%s is tracked at HEAD -- the retirement did not land" % RETIRED rc, out, err = git(repo, "rev-parse", "%s:%s" % (BLOB_REV, RETIRED)) if rc != 0 or not out: return "FAULT", "blob at %s:%s does not resolve: %s" % (BLOB_REV, RETIRED, err or "no output") if out != BLOB: return "FAULT", "blob moved: %s:%s reads %s, pinned %s" % (BLOB_REV, RETIRED, out[:12], BLOB[:12]) rc, size, _ = git(repo, "cat-file", "-s", BLOB) if rc != 0 or size != "249": return "FAULT", "blob %s size %r, expected 249 bytes" % (BLOB[:12], size) return "OK", "absent from tools/ at HEAD; blob %s resolves, %s bytes" % (BLOB[:12], size) def leg_contract(repo, verbose=False): tool = os.path.join(repo, "tools", "write_probe.py") if not os.path.isfile(tool): return "FAULT", "no tools/write_probe.py in %s" % repo rc, out, err = run([tool, "--selftest", "--repo", repo], timeout=900) tail = [l for l in (out or "").splitlines() if l.strip()][-1:] or [""] if rc == 0: return "OK", tail[0][:100] if verbose: print(out) detail = " ".join(l.strip() for l in (out or "").splitlines() if "FAIL" in l)[:180] or (err or "").strip()[:180] return "FAULT", "write_probe --selftest rc %s: %s" % (rc, detail) def leg_mutant(repo, verbose=False): """The retired bytes put back must red the same cell that caught them.""" with tempfile.TemporaryDirectory(prefix="q134-mutant-") as td: dst = os.path.join(td, "clone") rc, _, err = git(repo, "clone", "--quiet", "--no-hardlinks", repo, dst) if rc != 0: # Older gits refuse the four-argument local-clone form. rc, _, err = git(td, "clone", "--quiet", repo, "clone") if rc != 0: return "FAULT", "could not clone the graded tree: " + err[:140] rc, blob, err = git(dst, "cat-file", "blob", BLOB) if not blob: return "FAULT", "clone cannot read blob %s: %s" % (BLOB[:12], err[:120]) with open(os.path.join(dst, RETIRED), "w", encoding="utf-8", newline="") as fh: # git's output has already had its one trailing newline stripped by # git(), so the exact blob is `blob + "\n"`; the size check below is # what keeps that reasoning from being an assumption. fh.write(blob + "\n") got = os.path.getsize(os.path.join(dst, RETIRED)) if got != 249: return "FAULT", "restored copy is %d bytes, the blob is 249" % got for argv in (["add", RETIRED], ["-c", "user.email=volt@agents.invalid", "-c", "user.name=volt", "commit", "-q", "-m", "mutant: %s restored" % RETIRED]): rc, _, err = git(dst, *argv) if rc != 0: return "FAULT", "could not stage the mutant: " + err[:140] rc, out, err = run([os.path.join(dst, "tools", "write_probe.py"), "--selftest", "--repo", dst], timeout=900) if verbose: print(out) named = [l.strip() for l in (out or "").splitlines() if "FAIL" in l and "inspect_tree.py" in l] if rc != 1 or not named: return "FAULT", ("restored blob read rc %s, expected 1 naming " "inspect_tree.py: %s" % (rc, (named[0] if named else (out or "")[-120:]))) return "OK", "restored blob -> rc 1, " + named[0][:90] def main(argv=None): ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) ap.add_argument("--repo", default=DEFAULT_REPO) ap.add_argument("--verbose", action="store_true") a = ap.parse_args(argv) repo = os.path.abspath(a.repo) if not os.path.isdir(repo): print("q134: could not grade -- no such directory: " + repo) return 2 rc, _, err = git(repo, "rev-parse", "--git-dir") if rc != 0: print("q134: could not grade -- not a git worktree: " + repo) return 2 rc, head, _ = git(repo, "rev-parse", "--short", "HEAD") print("q134: %s at %s" % (repo, head or "?")) faults = 0 for name, fn in (("absence", leg_absence), ("contract", leg_contract), ("mutant", leg_mutant)): verdict, detail = (fn(repo) if fn is leg_absence else fn(repo, a.verbose)) if verdict != "OK": faults += 1 print(" %-9s %-5s %s" % (name, verdict, detail)) print("q134: 3 leg(s), %d passed, %d fault(s)" % (3 - faults, faults)) return 1 if faults else 0 if __name__ == "__main__": sys.exit(main())