null: the entry and its control locate their own checkout; a replay writes nothing and CHECK runs both (Q57 residual)
This commit is contained in:
1 parent
5cae75b672
commit
912e8a85d8
4 files changed
+206
-37
No files matched your search
Executable
+37
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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=<path> 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 "<none: this file is not in a git checkout>"))
|
||||
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")
|
||||
|
||||
+71
-18
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user