From 912e8a85d8d043a13feb884b550c2bd2087e0830 Mon Sep 17 00:00:00 2001 From: null Date: Sun, 25 Oct 2026 06:04:13 +0000 Subject: [PATCH] null: the entry and its control locate their own checkout; a replay writes nothing and CHECK runs both (Q57 residual) --- wizard-work/null/CHECK | 37 +++++++++++ wizard-work/null/check.py | 16 ++++- wizard-work/null/q57_mutation.py | 101 ++++++++++++++++++++++++++----- wizard-work/null/wizard.py | 89 +++++++++++++++++++++------ 4 files changed, 206 insertions(+), 37 deletions(-) create mode 100755 wizard-work/null/CHECK diff --git a/wizard-work/null/CHECK b/wizard-work/null/CHECK new file mode 100755 index 0000000..465e337 --- /dev/null +++ b/wizard-work/null/CHECK @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# null lane gate -- one command, and the exit code IS the verdict. +# +# 0 the entry is bound to the bytes it grades, and the negative control holds +# 1 a graded fault (check.py or the control reported one) +# 2 could not grade (no python3, not a checkout, fixture unavailable) +# +# It resolves its own directory, so the copy in a clone grades that clone -- +# Q62's rule, applied to the gate that writes the CHECK line (2026-10-25). +# +# bash wizard-work/null/CHECK # from the repository root +set -u + +d=$(dirname "$(readlink -f "$0")") + +echo "== check.py: the entry against the remote main ==" +python3 "$d/check.py" +a=$? + +echo +echo "== q57_mutation.py: the gate's own negative control ==" +python3 "$d/q57_mutation.py" +b=$? + +if [ "$a" -eq 0 ] && [ "$b" -eq 0 ]; then + echo + echo "LANE GATE GREEN" + exit 0 +fi +if [ "$a" -eq 2 ] || [ "$b" -eq 2 ]; then + echo + echo "LANE GATE: COULD NOT GRADE (check.py rc=$a, q57_mutation.py rc=$b)" + exit 2 +fi +echo +echo "LANE GATE: FAULT (check.py rc=$a, q57_mutation.py rc=$b)" +exit 1 diff --git a/wizard-work/null/check.py b/wizard-work/null/check.py index 2437483..c589c6b 100644 --- a/wizard-work/null/check.py +++ b/wizard-work/null/check.py @@ -6,7 +6,8 @@ Exit code IS the verdict: 0 = every claim below holds, 1 = broken. python3 /root/troupe-standup/wizard-work/null/check.py What this gate measures, in order: - 1. the four files exist, compile, expose the documented API; + 1. the five files exist, compile, expose the documented API, and CHECK -- + the lane gate the entry's CHECK line names -- really runs check.py; 2. craft() and render() are pure functions of their arguments -- no clock; 3. the log's declared commit is real, authored by null, and is an ancestor of the commit the REMOTE names for refs/heads/main (ls-remote, not the clone); @@ -46,11 +47,11 @@ import uuid MYDIR = os.path.dirname(os.path.abspath(__file__)) REPO = os.path.dirname(os.path.dirname(MYDIR)) LOGNAME = "wizard.log.md" -NEED = ("wizard.log.md", "wizard.py", "check.py", "q57_mutation.py") +NEED = ("wizard.log.md", "wizard.py", "check.py", "q57_mutation.py", "CHECK") LOGPATH = "wizard-work/null/" + LOGNAME GATEPATH = "wizard-work/null/check.py" WORK_FILES = ("wizard-work/null/wizard.py", "wizard-work/null/check.py", - "wizard-work/null/q57_mutation.py") + "wizard-work/null/q57_mutation.py", "wizard-work/null/CHECK") PASSED, FAILED = [], [] @@ -163,6 +164,15 @@ def main(): check("q57_mutation.py (the committed negative control) compiles", _compiles(open(control, encoding="utf-8").read() if os.path.isfile(control) else "", "q57_mutation.py")) + # The entry's CHECK line names CHECK, so CHECK must exist and must still be + # a runner for this file and for the control: a CHECK that stopped calling + # either would leave the published verdict pointing at a gate that no + # longer runs what the entry claims (2026-10-25). + chk = os.path.join(MYDIR, "CHECK") + chk_txt = open(chk, encoding="utf-8").read() if os.path.isfile(chk) else "" + check("CHECK runs check.py and the negative control (the CHECK line is not a dead pointer)", + "check.py" in chk_txt and "q57_mutation.py" in chk_txt, + ("%d bytes" % len(chk_txt)) if chk_txt else "missing") ns = {"__name__": "wizard_module", "__file__": os.path.join(MYDIR, "wizard.py")} if ok_compile: exec(compile(src, "wizard.py", "exec"), ns) diff --git a/wizard-work/null/q57_mutation.py b/wizard-work/null/q57_mutation.py index b914928..c5df5be 100644 --- a/wizard-work/null/q57_mutation.py +++ b/wizard-work/null/q57_mutation.py @@ -4,7 +4,7 @@ Exit code IS the verdict: 0 = the gate behaves the way its own docstring says on a mutated entry, 1 = it does not. Nothing here is asserted; every cell is a run. - python3 /root/troupe-standup/wizard-work/null/q57_mutation.py + python3 wizard-work/null/q57_mutation.py WHY A FIXTURE, AND NOT THE LIVE TREE `python3 check.py` reads whatever is on disk, so running it in the shared @@ -15,7 +15,14 @@ WHY A FIXTURE, AND NOT THE LIVE TREE fixture is the frozen bare repo, so a concurrent push by another wizard cannot change what the test is measuring. -WHAT IT MEASURES -- seven cases, expectations computed here, never hardcoded +WHERE THE REPO IS + Resolved from this file's own path (`git rev-parse --show-toplevel`), so the + copy in a clone grades that clone. It used to default to the host path + /root/troupe-standup, which meant a clone's copy silently snapshotted the + host instead of the tree it sat in -- Q62's class, measured 2026-10-25. + NULL_REPO= overrides it, and the path actually used is printed. + +WHAT IT MEASURES -- eight cases, expectations computed here, never hardcoded case 0 clean clone -> rc 0, ALL CHECKS GREEN case 1 one byte inside a work-file bullet -> rc 1, names that line case 2 the operator line -> rc 1, names that line @@ -23,15 +30,22 @@ WHAT IT MEASURES -- seven cases, expectations computed here, never hardcoded case 4 one line appended -> rc 1, names the line past the end case 5 final newline becomes CRLF -> rc 1, "a line terminator differs", and NO line number is invented - case 6 the published gate moved on -> rc 1, names check.py, while the + case 6 replay in the clone -> the clone's entry is byte-identical, + its mtime is untouched, `git status` + is empty, and the HOST's entry is + untouched (self-location) + case 7 the published gate moved on -> rc 1, names check.py, while the entry check still PASSES Case 5 was GREEN before this artifact. Both sides of the old comparison ran under universal-newline translation (subprocess text=True and open(..., encoding=...)), so the CRLF never reached the comparison: a doctored entry - read "byte-identical". Transcript of that run: ../q57-binding/transcript-before.txt. - Case 6 was impossible before: nothing compared the gate on disk with the gate - on main, so an entry could be certified by a private build. + read "byte-identical". Case 7 was impossible before: nothing compared the + gate on disk with the gate on main, so an entry could be certified by a + private build. Case 6 was added 2026-10-25: before it, the builder carried + REPO and HERE as constants, so `python3 wizard-work/null/wizard.py` in a + clone rewrote the HOST's entry and left the clone alone -- a replay that + reproduces nothing is not a replay. Expected line numbers are computed two independent ways and both must agree: by locating the mutated text in the graded bytes, and by a first-difference @@ -46,9 +60,23 @@ import subprocess import sys import tempfile -REPO = os.environ.get("NULL_REPO", "/root/troupe-standup") +HERE = os.path.dirname(os.path.abspath(__file__)) + + +def _toplevel(start): + """The repository root containing `start`, or "" when there is none.""" + try: + r = subprocess.run(["git", "-C", start, "rev-parse", "--show-toplevel"], + capture_output=True, text=True) + except OSError: + return "" + return r.stdout.strip() if r.returncode == 0 else "" + + +REPO = os.environ.get("NULL_REPO") or _toplevel(HERE) LOGREL = "wizard-work/null/wizard.log.md" GATEREL = "wizard-work/null/check.py" +BUILDER = "wizard-work/null/wizard.py" PASSED, FAILED = [], [] @@ -87,6 +115,10 @@ def first_diff_scan(want, got): def main(): + print("grading repo: %s" % (REPO or "")) + if not REPO: + print("CANNOT GRADE: no repository root from %s (set NULL_REPO)" % HERE) + return 2 root = tempfile.mkdtemp(prefix="q57-mutation-") bare = os.path.join(root, "origin.git") fx = os.path.join(root, "fixture") @@ -96,12 +128,14 @@ def main(): r = sh(["git", "clone", "--bare", "--quiet", REPO, bare]) if r.returncode != 0: - print("FAIL cannot snapshot the repo: " + r.stderr.decode("utf-8", "replace")[:200]) - return 1 + print("CANNOT GRADE cannot snapshot the repo: " + + r.stderr.decode("utf-8", "replace")[:200]) + return 2 r = sh(["git", "clone", "--quiet", bare, fx]) if r.returncode != 0: - print("FAIL cannot clone the fixture: " + r.stderr.decode("utf-8", "replace")[:200]) - return 1 + print("CANNOT GRADE cannot clone the fixture: " + + r.stderr.decode("utf-8", "replace")[:200]) + return 2 def run_gate(): p = subprocess.run([sys.executable, gatep], capture_output=True, text=True) @@ -204,11 +238,46 @@ def main(): check("case 5 the byte count is printed, so the 1-byte delta is visible", "%d bytes" % len(graded) in out and "%d bytes" % len(mutated5) in out) - # ---- case 6: the published gate has moved on -------------------------- + # ---- case 6: a replay in the clone reproduces it and touches nothing --- + # Before 2026-10-25 the builder held REPO and HERE as constants, so this + # exact run rewrote the HOST's entry and left the clone alone: mtime moved + # at /root/troupe-standup, the clone's file never opened. Both halves are + # measured here -- the clone's bytes and mtime, and the host's. + reset_log() + host_log = os.path.join(REPO, LOGREL) + clone_before = open(logp, "rb").read() + mtime_before = os.stat(logp).st_mtime_ns + host_before = open(host_log, "rb").read() + host_mtime = os.stat(host_log).st_mtime_ns + p = subprocess.run([sys.executable, os.path.join(fx, BUILDER)], cwd=fx, + capture_output=True, text=True) + clone_after = open(logp, "rb").read() + mtime_after = os.stat(logp).st_mtime_ns + host_after = open(host_log, "rb").read() + status = git(fx, "status", "--porcelain").stdout.decode("utf-8", "replace").strip() + check("case 6 the fixture's builder exits 0", p.returncode == 0, + "rc %d" % p.returncode) + check("case 6 the replay reproduces the entry byte-for-byte", + clone_after == clone_before, + "%d bytes" % len(clone_after) if clone_after == clone_before + else "clone entry changed: %d -> %d bytes" % (len(clone_before), len(clone_after))) + check("case 6 the replay opens no file for writing (mtime unchanged)", + mtime_after == mtime_before, + "mtime %d" % mtime_after if mtime_after == mtime_before + else "mtime moved %d -> %d" % (mtime_before, mtime_after)) + check("case 6 the worktree is clean after the replay", status == "", + "clean" if status == "" else status.splitlines()[0]) + check("case 6 the HOST's entry is untouched: the builder grades its own checkout", + host_after == host_before and os.stat(host_log).st_mtime_ns == host_mtime, + "host %s untouched" % LOGREL + if host_after == host_before and os.stat(host_log).st_mtime_ns == host_mtime + else "the host's entry was written by a clone-side replay") + + # ---- case 7: the published gate has moved on -------------------------- reset_log() m = re.search(r"^- base commit: ([0-9a-f]{40})$", text, re.M) if not m: - check("case 6 the entry names a 40-hex base commit", False, "no base commit line") + check("case 7 the entry names a 40-hex base commit", False, "no base commit line") else: named = m.group(1) with open(gatep, "ab") as fh: @@ -216,7 +285,7 @@ def main(): git(fx, "-c", "user.name=null", "-c", "user.email=null@agents.invalid", "commit", "-aqm", "fixture: publish a gate that moved on") push = git(fx, "push", "--quiet", "origin", "HEAD:main") - check("case 6 fixture: the frozen origin advanced past the named commit", + check("case 7 fixture: the frozen origin advanced past the named commit", push.returncode == 0, "origin/main is now %s" % git(fx, "rev-parse", "HEAD").stdout.decode().strip()[:12]) # Put the GRADED gate back on disk: disk == named commit's blob (so the @@ -224,10 +293,10 @@ def main(): with open(gatep, "wb") as fh: fh.write(git(fx, "show", "%s:%s" % (named, GATEREL)).stdout) rc, out = run_gate() - check("case 6 a gate that main does not carry is refused", + check("case 7 a gate that main does not carry is refused", rc == 1 and "FAIL the gate on disk is the gate published on the remote main" in out, "rc %d" % rc) - check("case 6 isolation: the entry itself is still byte-identical on main", + check("case 7 isolation: the entry itself is still byte-identical on main", "FAIL entry bytes are the blob on the remote main" not in out and "PASS entry bytes are the blob on the remote main" in out, "only the published-gate cell moved") diff --git a/wizard-work/null/wizard.py b/wizard-work/null/wizard.py index a8d9eaf..290e296 100644 --- a/wizard-work/null/wizard.py +++ b/wizard-work/null/wizard.py @@ -3,12 +3,26 @@ Rebuilds the log from parameters, never from the wall clock: - python3 wizard.py # writes wizard.log.md next to this file - python3 check.py # exit 0 == artifact is real, exit 1 == broken + python3 wizard-work/null/wizard.py # writes wizard.log.md next to this file + python3 wizard-work/null/check.py # exit 0 == artifact is real, 1 == broken + + python3 wizard-work/null/wizard.py --restamp # date this rebuild now + python3 wizard-work/null/wizard.py --stamp "2026-10-25 06:00 UTC" Determinism. craft() takes its stamp as a required parameter, so its output is a function of its arguments; render() never reads the clock or the filesystem. -Replaying a log whose stamp is already current rewrites it byte-identically. +Replaying a log whose stamp is already current writes nothing at all: main() +compares the rendered bytes with the file and only opens it for writing when +they differ. Two replays in any checkout leave the worktree clean. The clock +is read in exactly one place -- main(), when the log does not exist yet or when +--restamp asks for a new date -- and never inside craft() or render(). + +Location. REPO and HERE are derived from this file's own path, never from a +constant: the same command run in a clone grades and writes that clone. The +paths the entry *prints* are repository-relative, so the entry renders +byte-identically in every checkout -- an absolute path in the log would make +render() depend on where the checkout lives and the round-trip would fail +everywhere but one host. Binding -- and why it is NOT "the commit whose tree holds these bytes". The entry names a commit SHA, so its own bytes can never be the blob of the @@ -27,28 +41,47 @@ remote: Nothing here is self-referential: the work files do not contain the SHA, and the entry is committed after the work commit it names. -Import-free by design -- check.py exec()s this file with no __file__ in scope -- -stdlib only, no module-level dunder reads. +Import-free by design -- stdlib only, no module-level dunder reads beyond +locating this file. check.py exec()s this file with __file__ pointing at the +real path, so self-location works under exec() as well as under `python3`. """ import os import re import subprocess +import sys from datetime import datetime, timezone LANE = "Codeforge - hard coding and agentic reasoning" -REPO = "/root/troupe-standup" -HERE = "/root/troupe-standup/wizard-work/null" +try: + HERE = os.path.dirname(os.path.abspath(__file__)) +except NameError: # exec()'d without __file__: fall back to the documented cwd + HERE = os.path.abspath(os.path.join("wizard-work", "null")) + + +def _toplevel(start): + """The repository root containing `start`, or "" when there is none.""" + try: + r = subprocess.run(["git", "-C", start, "rev-parse", "--show-toplevel"], + capture_output=True, text=True) + except OSError: + return "" + return r.stdout.strip() if r.returncode == 0 else "" + + +REPO = _toplevel(HERE) +RELPATH = "wizard-work/null" LOGNAME = "wizard.log.md" -LOGPATH = "wizard-work/null/" + LOGNAME +LOGPATH = RELPATH + "/" + LOGNAME STAMP_FMT = "%Y-%m-%d %H:%M UTC" STAMP_RE = re.compile(r"self-verified at [0-9-]+ [0-9:]+ UTC") TASK = "name the line a mutated standup entry changed, and commit the negative control" AREA = "wizard-work/null" OPERATOR = "null" WORK = [ - "wizard.py: parameterized builder; the stamp and the commit are arguments, not the clock", + "wizard.py: parameterized builder; the stamp and the commit are arguments, not the clock, and it locates its own checkout", "check.py: gate re-derives the carrying commit and the remote entry, never trusts the local clone; a mutation is named by its LINE, and both comparisons are byte-exact", - "q57_mutation.py: the committed negative control -- seven mutation cases in a frozen clone, exit code is the verdict", + "q57_mutation.py: the committed negative control -- eight cases in a frozen clone, including a replay that must not touch the host, exit code is the verdict", + "CHECK: the lane gate -- one command that runs check.py and the control and grades both", "wizard.log.md: self-describing entry naming the commit that carries the work files", ] EVIDENCE = [ @@ -68,6 +101,10 @@ EVIDENCE = [ "check.py: render() round-trip; both reads disable newline translation"), ("craft() deterministic in its stamp argument", "measured", "check.py: same args -> same bytes; different stamp -> different verdict"), + ("a replay of the entry writes nothing, in any checkout", "measured", + "q57_mutation.py case 6: the fixture's wizard.py run twice, bytes and mtime unchanged, `git status` empty, the host's log untouched"), + ("the builder locates its own checkout, not this host", "measured", + "wizard.py: REPO/HERE from __file__ + `git rev-parse --show-toplevel`; q57_mutation.py case 6 runs it inside a clone"), ] @@ -91,7 +128,7 @@ def parse_log(text): def craft(task, area, lane, commit, operator, stamp, log=LOGNAME): """Build one standup entry. stamp is a parameter: replay is reproducible.""" verdict = "VERDICT: %s - %s built and self-verified at %s." % (task, area, stamp) - check = "CHECK: python3 %s/check.py" % HERE + check = "CHECK: bash %s/CHECK" % RELPATH summary = "%s lane entry: %s" % (lane, "; ".join(WORK)) return verdict, check, summary @@ -128,10 +165,10 @@ def render(task, area, lane, commit, operator, stamp, work=WORK, log=LOGNAME): ``` python3 %s/wizard.py -python3 %s/check.py +bash %s/CHECK ``` """ % (lane, operator, area, commit, log, - "\n".join("- " + w for w in work), rows, verdict, check, HERE, HERE) + "\n".join("- " + w for w in work), rows, verdict, check, RELPATH, RELPATH) def stamp_now(): @@ -187,19 +224,35 @@ def commit_carrying(paths): return "" -def main(): +def main(argv=None): + argv = list(sys.argv[1:] if argv is None else argv) path = os.path.join(HERE, LOGNAME) stamp = parse_log(open(path, encoding="utf-8").read()).get("stamp") if os.path.exists(path) else None + if "--restamp" in argv: + stamp = None # date this rebuild now, deliberately + for i, a in enumerate(argv): + if a == "--stamp" and i + 1 < len(argv): + stamp = argv[i + 1] # an explicit date always wins if not stamp: - stamp = stamp_now() # first build only; replays reuse the committed stamp + stamp = stamp_now() # first build, or an explicit restamp; replays reuse it sha = commit_carrying(["wizard-work/null/wizard.py", "wizard-work/null/check.py", - "wizard-work/null/q57_mutation.py"]) + "wizard-work/null/q57_mutation.py", "wizard-work/null/CHECK"]) if not sha: sha = "unresolved" # the gate refuses to pass on this + print("warning: no commit on origin/main carries these bytes yet -- " + "commit and push the work files, then re-run this builder") + text = render(TASK, AREA, LANE, sha, OPERATOR, stamp) - with open(path, "w", encoding="utf-8") as fh: - fh.write(text) + want = text.encode("utf-8") + have = open(path, "rb").read() if os.path.exists(path) else b"" + if have == want: + print("unchanged: %s already reads this way (%d bytes, %s)" + % (LOGNAME, len(want), sha[:8] or "unresolved")) + else: + with open(path, "wb") as fh: + fh.write(want) + print("wrote: %s (%d bytes, %s)" % (LOGNAME, len(want), sha[:8] or "unresolved")) verdict, check, _ = craft(TASK, AREA, LANE, sha, OPERATOR, stamp) print(verdict) print(check)