volt: Q90 -- tree_root.py gets a root boundary, a seed check, and an import guard six spellings wide

marker + .git must sit in the same directory, the walk is bounded at 64
ancestors, and portable_seed raises instead of returning a path to nothing.
Cells 6 -> 14, lane gate 587 -> 595 tests, and wizard-work/volt/CHECK-q90
(7 legs) grades each done-mean with a mutant that must red it.
This commit is contained in:
ledger committed 2026-10-30 23:42:26 +00:00
1 parent d0ba06e7de
commit 232c8af304
7 files changed
+481 -45

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
# Q90 CHECK -- tree_root.py's root boundary, its seed existence, and the
# import-time-read model, each graded by a mutant that must red it.
#
# rc 0 = every leg as expected; 1 = a graded fault; 2 = could not grade.
# The work is done by wizard-work/volt/q90_verify.py beside this file; every
# leg runs in a temp copy of the lane, so the tree this instrument ships in is
# never mutated. Run it from any checkout.
set -u
REPO="$(cd "$(dirname "$0")/../.." && pwd)" || exit 2
if ! cd "$REPO"; then
echo "q90: could not grade -- cannot cd to $REPO"
exit 2
fi
if ! command -v python3 >/dev/null 2>&1; then
echo "q90: could not grade -- no python3 on PATH"
exit 2
fi
exec python3 wizard-work/volt/q90_verify.py
+167
View File
@@ -0,0 +1,167 @@
#!/usr/bin/env python3
"""Q90 instrument: grade tree_root.py's four done-means, and prove each cell bites.
The shared tree is never mutated. Every leg runs in a temp copy of the lane
(or of the four files a cell needs), and every mutant is written into a copy.
Legs
1. control small tree -- tree_root.py's 14 cells all pass under
run_lane_tests.py, rc 0, printed count == defs
2. gate reaches cells -- the *lane's own* CHECK, run in a full copy of
wizard-work/beam/ with the decoy fixed module
swapped for the accepting one, exits 1 and names
the decoy cell (Q128's runner collects it, so a
green lane gate cannot hide this file)
3. decoy marker -- mutant: marker alone accepted again -> rc 1
4. depth bound -- mutant: depth test removed -> rc 1
5. seed existence -- mutant: isfile raise removed -> rc 1
6. import-time read -- mutant: a real module-scope Path.read_text()
appended to tree_root.py -> rc 1
7. guard model narrowed -- mutant: one spelling dropped from the test's
model table -> rc 1 on the set-equality cell
Exit codes follow the repo's tools/ contract: 0 every leg as expected,
1 a leg disagreed, 2 could not grade (missing lane files, runner crashed).
"""
import os
import re
import shutil
import subprocess
import sys
import tempfile
HERE = os.path.dirname(os.path.abspath(__file__))
REPO = os.path.dirname(os.path.dirname(HERE))
LANE = os.path.join(REPO, "wizard-work", "beam")
SMALL = ("tree_root.py", "test_tree_root.py", "beam_assert.py", "run_lane_tests.py")
FAILURES = []
LEGS = [0]
def leg(name, ok, detail):
LEGS[0] += 1
status = "PASS" if ok else "FAULT"
print("%s %-24s %s" % (status, name, detail))
if not ok:
FAILURES.append(name)
def run(cwd, argv, timeout=300):
p = subprocess.run(argv, cwd=cwd, capture_output=True, text=True,
timeout=timeout)
return p.returncode, p.stdout + p.stderr
def small_copy(mutate=None):
"""Copy the four files a cell needs; apply mutate(dict path->text)."""
d = tempfile.mkdtemp(prefix="q90-")
for n in SMALL:
shutil.copyfile(os.path.join(LANE, n), os.path.join(d, n))
if mutate:
for name, fn in mutate.items():
path = os.path.join(d, name)
with open(path) as fh:
text = fh.read()
out = fn(text)
if out == text:
raise SystemExit("mutant for %s did not change the file" % (name,))
with open(path, "w") as fh:
fh.write(out)
return d
def lane_copy(mutate=None):
d = tempfile.mkdtemp(prefix="q90-lane-")
dest = os.path.join(d, "beam")
shutil.copytree(LANE, dest, ignore=shutil.ignore_patterns("__pycache__"))
if mutate:
for name, fn in mutate.items():
path = os.path.join(dest, name)
with open(path) as fh:
text = fh.read()
with open(path, "w") as fh:
fh.write(fn(text))
return dest
def sub(text, old, new):
if old not in text:
raise SystemExit("anchor not found: %r" % (old,))
return text.replace(old, new, 1)
def defs(path):
with open(path) as fh:
return re.findall(r"^def (test_\w+)\(\):", fh.read(), re.M)
def main():
for n in SMALL:
if not os.path.isfile(os.path.join(LANE, n)):
raise SystemExit("cannot grade: missing wizard-work/beam/%s" % n)
want = len(defs(os.path.join(LANE, "test_tree_root.py")))
if want < 10:
raise SystemExit("cannot grade: test_tree_root.py exposes %d cells" % want)
# 1. control
d = small_copy()
rc, out = run(d, [sys.executable, "run_lane_tests.py"])
m = re.search(r"(\d+) bare case\(s\)", out)
got = int(m.group(1)) if m else -1
leg("control", rc == 0 and got == want,
"rc=%d bare=%d want=%d" % (rc, got, want))
# 2. the lane's own gate must reach these cells
d = lane_copy({"tree_root.py": lambda t: sub(
t,
'if not require_git or os.path.exists(os.path.join(cur, ".git")):',
"if True:")})
rc, out = run(d, ["bash", "CHECK"])
leg("gate-reaches-cells",
rc == 1 and "test_find_root_ignores_decoy_marker" in out,
"lane CHECK rc=%d decoy cell named=%s"
% (rc, "test_find_root_ignores_decoy_marker" in out))
mutants = [
("decoy-marker", "tree_root.py", lambda t: sub(
t,
'if not require_git or os.path.exists(os.path.join(cur, ".git")):',
"if True:"), "test_find_root_ignores_decoy_marker"),
("depth-bound", "tree_root.py", lambda t: sub(
t, "if parent == cur or depth > max_depth:", "if parent == cur:"),
"test_find_root_respects_depth_bound"),
("seed-existence", "tree_root.py", lambda t: sub(
t, "if not os.path.isfile(p):", "if False:"),
"test_portable_seed_missing_raises"),
("import-read", "tree_root.py", lambda t: (
t + "\nfrom pathlib import Path as _ProbePath\n"
"_ProbePath(__file__).read_text()\n"), "test_import_no_io"),
("model-narrowed", "test_tree_root.py", lambda t: sub(
t, ' "Path.read_text": "from pathlib import Path\\n'
'Path(__file__).read_text()\\n",\n', ""),
"test_import_io_model_is_exactly_the_listed_set"),
]
for name, fname, fn, cell in mutants:
d = small_copy({fname: fn})
rc, out = run(d, [sys.executable, "run_lane_tests.py"])
leg(name, rc == 1 and cell in out,
"rc=%d red=%s" % (rc, cell if cell in out else "not-named"))
if LEGS[0] != 7:
raise SystemExit("cannot grade: ran %d legs, expected 7" % LEGS[0])
if FAILURES:
print("q90: %d leg(s), %d fault -- %s"
% (LEGS[0], len(FAILURES), ", ".join(FAILURES)))
return 1
print("q90: %d leg(s), 0 fault -- OK" % LEGS[0])
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except subprocess.TimeoutExpired:
print("q90: could not grade -- a leg timed out")
sys.exit(2)