null: bind the standup entry to the commit whose blob is byte-identical
This commit is contained in:
1 parent
31a37a305c
commit
3222860fb0
3 files changed
+341
-136
No files matched your search
+214
-92
@@ -1,69 +1,253 @@
|
||||
#!/usr/bin/env python3
|
||||
"""null verification for the Wizard Troupe standup.
|
||||
|
||||
Exit code is the verdict: 0 = everything holds, 1 = something broke.
|
||||
Exit code IS the verdict: 0 = every claim below holds, 1 = broken.
|
||||
|
||||
Run: python3 /root/troupe-standup/wizard-work/null/check.py
|
||||
python3 /root/troupe-standup/wizard-work/null/check.py
|
||||
|
||||
Self-run guard: the recursive probe runs this same file with
|
||||
NULL_CHECK_SELF=1, which makes the probe inert (report success without
|
||||
re-executing). Without the guard the probe would re-arm the variable and
|
||||
recurse forever.
|
||||
What this gate measures, in order:
|
||||
1. the three files exist, compile, expose the documented API;
|
||||
2. craft() and render() are pure functions of their arguments -- no clock;
|
||||
3. binding: the log's own declared base commit is a real commit, is authored
|
||||
by null, and its blob of this file is BYTE-IDENTICAL to the log on disk.
|
||||
The commit is not required to be the newest one touching the path -- it
|
||||
must be the one whose tree holds these bytes, which is exactly what the
|
||||
builder writes, so a stale commit can no longer be named over fresh bytes;
|
||||
4. that commit is on the REMOTE main, verified against `git ls-remote`, not
|
||||
the local clone, and the remote's tree is re-read for the three files;
|
||||
5. a child process really ran and exited 0 -- a nonce the child must echo,
|
||||
so the self-run line cannot pass by returning True without spawning.
|
||||
|
||||
The self-run child sets NULL_CHECK_NONCE and exits before any check is
|
||||
evaluated, so the gate never grades its own verdict: it proves only that this
|
||||
file spawns, runs to completion, and echoes.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
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")
|
||||
LOGPATH = "wizard-work/null/" + LOGNAME
|
||||
PASSED, FAILED = [], []
|
||||
|
||||
|
||||
def check(name, ok, detail=""):
|
||||
ok = bool(ok)
|
||||
(PASSED if ok else FAILED).append(name)
|
||||
print(("PASS " if ok else "FAIL ") + name + (" -> " + detail if detail else ""))
|
||||
|
||||
|
||||
def run(args, **kw):
|
||||
return subprocess.run(args, capture_output=True, text=True, **kw)
|
||||
|
||||
|
||||
def git(*args):
|
||||
return run(["git", "-C", REPO] + list(args))
|
||||
|
||||
|
||||
# --- the child branch: prove this gate spawns, runs, and echoes, then exit --
|
||||
_nonce = os.environ.get("NULL_CHECK_NONCE")
|
||||
if _nonce:
|
||||
print("NONCE " + _nonce)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def _compiles(src, name):
|
||||
try:
|
||||
compile(src, name, "exec")
|
||||
return True
|
||||
except SyntaxError:
|
||||
return False
|
||||
|
||||
|
||||
def _name_differing_line(commit, other):
|
||||
r = git("show", "%s:%s" % (commit, LOGPATH))
|
||||
if r.returncode != 0:
|
||||
return
|
||||
a, b = r.stdout.splitlines(), (other or "").splitlines()
|
||||
for i in range(max(len(a), len(b))):
|
||||
x = a[i] if i < len(a) else "<missing>"
|
||||
y = b[i] if i < len(b) else "<missing>"
|
||||
if x != y:
|
||||
print(" differing line %d:\n committed: %s\n rendered: %s"
|
||||
% (i + 1, x, y))
|
||||
return
|
||||
|
||||
|
||||
def _self_run(nonce):
|
||||
"""Spawn check.py with a nonce; return (ok, output) or None if it never ran.
|
||||
|
||||
ok is True only when a child process really spawned, echoed our nonce back,
|
||||
and exited 0. The child exits before any check is evaluated (see the guard
|
||||
at the top of this file), so this proves the gate runs, not that it is right.
|
||||
"""
|
||||
env = dict(os.environ, NULL_CHECK_NONCE=nonce)
|
||||
try:
|
||||
r = run([sys.executable, os.path.join(MYDIR, "check.py")], env=env, timeout=900)
|
||||
except Exception as e: # noqa: BLE001
|
||||
print(" self-run: %s: %s" % (type(e).__name__, e))
|
||||
return None
|
||||
return r.returncode == 0 and ("NONCE %s" % nonce) in r.stdout, r.stdout + r.stderr
|
||||
|
||||
|
||||
def _remote_main():
|
||||
"""The commit the REMOTE names for refs/heads/main, or '' if unreachable."""
|
||||
r = run(["git", "-C", REPO, "ls-remote", "origin", "refs/heads/main"])
|
||||
if r.returncode != 0 or not r.stdout.strip():
|
||||
return ""
|
||||
return r.stdout.split()[0]
|
||||
|
||||
|
||||
def _remote_ok(commit):
|
||||
"""True iff `commit` is null's, carries these files, and is on the REMOTE main.
|
||||
|
||||
ls-remote asks the remote which commit refs/heads/main names; a local clone
|
||||
can be stale or ahead, so the local ref proves nothing about the push.
|
||||
"""
|
||||
if not commit:
|
||||
return False, "no base commit to inspect"
|
||||
who = git("show", "-s", "--format=%an|%s", commit)
|
||||
if who.returncode != 0:
|
||||
return False, "commit unreadable"
|
||||
author, subject = who.stdout.strip().split("|", 1)
|
||||
if author != "null":
|
||||
return False, "commit %s authored by %r, not null" % (commit[:8], author)
|
||||
files = git("show", "--name-only", "--format=", commit).stdout.split()
|
||||
need = {"wizard-work/null/" + f for f in NEED}
|
||||
if not need.issubset(set(files)):
|
||||
return False, "commit missing files: %s" % sorted(need - set(files))
|
||||
head = _remote_main()
|
||||
if not head:
|
||||
return False, "ls-remote could not reach origin/main"
|
||||
anc = git("merge-base", "--is-ancestor", commit, head)
|
||||
if anc.returncode != 0:
|
||||
return False, "commit %s not an ancestor of origin/main (%s)" % (commit[:8], head[:8])
|
||||
# re-read the three files from the commit the remote actually names
|
||||
for f in NEED:
|
||||
blob = git("show", "%s:wizard-work/null/%s" % (head, f))
|
||||
if blob.returncode != 0:
|
||||
return False, "origin/main lacks wizard-work/null/%s" % f
|
||||
local = os.path.join(MYDIR, f)
|
||||
if os.path.isfile(local):
|
||||
with open(local, encoding="utf-8") as fh:
|
||||
if fh.read() != blob.stdout:
|
||||
return False, "%s on disk != origin/main's blob" % f
|
||||
return True, "%s by null (%s) is an ancestor of origin/main %s; its tree matches the disk" % (
|
||||
commit[:8], subject, head[:8])
|
||||
|
||||
|
||||
def main():
|
||||
# --- 1. artifact presence (all three files) ---
|
||||
for fn in ("wizard.log.md", "wizard.py", "check.py"):
|
||||
# --- 1. presence / compile / API --------------------------------------
|
||||
for fn in NEED:
|
||||
check("artifact present: " + fn, os.path.isfile(os.path.join(MYDIR, fn)))
|
||||
|
||||
# --- 2. wizard.py compiles, exposes the expected API ---
|
||||
src = open(os.path.join(MYDIR, "wizard.py")).read()
|
||||
check("wizard.py compiles", _compiles(src))
|
||||
src = open(os.path.join(MYDIR, "wizard.py"), encoding="utf-8").read()
|
||||
check("wizard.py compiles", _compiles(src, "wizard.py"))
|
||||
ns = {"__name__": "wizard_module", "__file__": os.path.join(MYDIR, "wizard.py")}
|
||||
if _compiles(src):
|
||||
if _compiles(src, "wizard.py"):
|
||||
exec(compile(src, "wizard.py", "exec"), ns)
|
||||
check("API: craft exists", callable(ns.get("craft")))
|
||||
check("API: render exists", callable(ns.get("render")))
|
||||
check("API: VERDICT/CHECK markers exist", "VERDICT:" in src and "CHECK:" in src)
|
||||
|
||||
# --- 3. craft() unit test: deterministic, non-empty, format correct ---
|
||||
# --- 2. craft() / render() are pure in their arguments -----------------
|
||||
try:
|
||||
verdict, chk, summary = ns["craft"](
|
||||
"fix the build", "staging", "Codeforge", "d7a1f", "alex"
|
||||
)
|
||||
ok = bool(verdict) and chk.startswith("CHECK: ") and isinstance(summary, str) and summary
|
||||
check("craft() returns VERDICT/CHECK/summary", ok,
|
||||
repr((verdict, chk[:40] + "...", summary[:24])))
|
||||
args = ("t", "a", "L", "deadbeef", "null", "2026-10-24 00:00 UTC")
|
||||
v1, c1, _ = ns["craft"](*args)
|
||||
v2, c2, _ = ns["craft"](*args)
|
||||
v3, _, _ = ns["craft"]("t", "a", "L", "deadbeef", "null", "2030-01-01 00:00 UTC")
|
||||
check("craft() deterministic in its stamp argument",
|
||||
(v1, c1) == (v2, c2) and v1 != v3 and c1.startswith("CHECK: "),
|
||||
"same stamp -> identical bytes; different stamp -> different verdict")
|
||||
except Exception as e: # noqa: BLE001
|
||||
check("craft() returns VERDICT/CHECK/summary", False, "%s: %s" % (type(e).__name__, e))
|
||||
check("craft() deterministic in its stamp argument", False,
|
||||
"%s: %s" % (type(e).__name__, e))
|
||||
|
||||
# --- 4. report parses: exactly one VERDICT: and one CHECK: ---
|
||||
log = open(os.path.join(MYDIR, "wizard.log.md")).read()
|
||||
nv = len(re.findall(r"(?m)^VERDICT:", log))
|
||||
nc = len(re.findall(r"(?m)^CHECK:", log))
|
||||
check("wizard.log.md has exactly one VERDICT:", nv == 1, "found %d" % nv)
|
||||
check("wizard.log.md has exactly one CHECK:", nc == 1, "found %d" % nc)
|
||||
# --- 3. binding: the declared commit's blob IS the log on disk ----------
|
||||
log_path = os.path.join(MYDIR, LOGNAME)
|
||||
disk = open(log_path, encoding="utf-8").read() if os.path.exists(log_path) else ""
|
||||
fields = dict(ns["parse_log"](disk)) if callable(ns.get("parse_log")) else {}
|
||||
lane = fields.get("lane", "")
|
||||
area = fields.get("target area", "")
|
||||
operator = fields.get("operator", "null")
|
||||
commit = fields.get("base commit", "")
|
||||
stamp = fields.get("stamp", "")
|
||||
|
||||
# --- 5. self-verification: run check.py and require exit 0 ---
|
||||
check("check.py self-run exits 0", _self_run(), "")
|
||||
rendered = None
|
||||
try:
|
||||
rendered = ns["render"](lane, area, lane, commit, operator, stamp)
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
# --- 6. git hygiene: commit exists and pushed HEAD is a descendant of it ---
|
||||
ok, detail = _git_ok()
|
||||
check("log declares a base commit SHA", bool(commit), repr(commit))
|
||||
obj = git("cat-file", "-t", commit) if commit else None
|
||||
check("base commit resolves as a git object",
|
||||
bool(obj and obj.returncode == 0 and obj.stdout.strip() == "commit"),
|
||||
(obj.stdout.strip() if obj else "no sha") or (obj.stderr.strip() if obj else ""))
|
||||
|
||||
if commit and obj and obj.returncode == 0:
|
||||
author = git("show", "-s", "--format=%an", commit).stdout.strip()
|
||||
check("declared commit is authored by null", author == "null", author)
|
||||
blob = git("show", "%s:%s" % (commit, LOGPATH))
|
||||
if blob.returncode != 0:
|
||||
check("log on disk == git blob of the declared commit", False,
|
||||
"git show failed: " + blob.stderr.strip()[:120])
|
||||
elif disk == blob.stdout:
|
||||
check("log on disk == git blob of the declared commit", True,
|
||||
"%d bytes, byte-identical" % len(disk.encode()))
|
||||
else:
|
||||
check("log on disk == git blob of the declared commit", False,
|
||||
"%d bytes on disk vs %d in the commit" % (len(disk.encode()), len(blob.stdout.encode())))
|
||||
_name_differing_line(commit, disk)
|
||||
else:
|
||||
check("declared commit is authored by null", False, "no commit to read")
|
||||
check("log on disk == git blob of the declared commit", False, "no commit to read")
|
||||
|
||||
check("fresh render with the log's stamp == log",
|
||||
rendered is not None and rendered == disk,
|
||||
"render() round-trip, byte-for-byte" if rendered == disk
|
||||
else "render() unavailable or differs")
|
||||
|
||||
# --- 4. shape of the log -----------------------------------------------
|
||||
nv = len(re.findall(r"(?m)^VERDICT:", disk))
|
||||
nc = len(re.findall(r"(?m)^CHECK:", disk))
|
||||
check("log has exactly one VERDICT:", nv == 1, "found %d" % nv)
|
||||
check("log has exactly one CHECK:", nc == 1, "found %d" % nc)
|
||||
check("log carries its own stamp", bool(stamp), repr(stamp))
|
||||
|
||||
# --- 5. the commit is really on the REMOTE main ------------------------
|
||||
ok, detail = _remote_ok(commit)
|
||||
check("commit pushed to origin/main", ok, detail)
|
||||
|
||||
# --- 6. replay: the builder rewrites the log byte-identically ----------
|
||||
try:
|
||||
a = ns["render"](lane, area, lane, commit, operator, stamp)
|
||||
b = ns["render"](lane, area, lane, commit, operator, stamp)
|
||||
check("render() stable across calls (no clock in it)", a == b == disk,
|
||||
"%d vs %d bytes" % (len(a.encode()), len(b.encode())))
|
||||
except Exception as e: # noqa: BLE001
|
||||
check("render() stable across calls (no clock in it)", False,
|
||||
"%s: %s" % (type(e).__name__, e))
|
||||
|
||||
# --- 7. self-run: a child really spawned and echoed the nonce ----------
|
||||
n = uuid.uuid4().hex
|
||||
child = _self_run(n)
|
||||
if child is None:
|
||||
check("self-run spawns a child that echoes the nonce and exits 0", False,
|
||||
"child did not echo nonce " + n[:8])
|
||||
else:
|
||||
ok, out = child
|
||||
check("self-run spawns a child that echoes the nonce and exits 0", ok,
|
||||
"nonce %s echoed" % n[:8] if ok else "child exited without echoing")
|
||||
if not ok:
|
||||
print(" child output:\n" + "\n".join(
|
||||
" " + l for l in (out or "").strip().splitlines()[-8:]))
|
||||
|
||||
print("\n%d passed, %d failed" % (len(PASSED), len(FAILED)))
|
||||
if FAILED:
|
||||
print("FAILED: " + ", ".join(FAILED))
|
||||
@@ -72,67 +256,5 @@ def main():
|
||||
return 0
|
||||
|
||||
|
||||
def _self_run():
|
||||
"""Re-execute check.py under an inert marker env var; True iff it exits 0.
|
||||
|
||||
The child sees NULL_CHECK_SELF=1, so its own _self_run() reports True
|
||||
without re-executing. That bounds the recursion depth to exactly one
|
||||
child process instead of an unbounded chain.
|
||||
"""
|
||||
if os.environ.get("NULL_CHECK_SELF") == "1":
|
||||
return True
|
||||
env = dict(os.environ, NULL_CHECK_SELF="1")
|
||||
try:
|
||||
r = subprocess.run([sys.executable, os.path.join(MYDIR, "check.py")],
|
||||
capture_output=True, text=True, env=env, timeout=120)
|
||||
return r.returncode == 0
|
||||
except Exception: # noqa: BLE001
|
||||
return False
|
||||
|
||||
|
||||
def _compiles(src):
|
||||
try:
|
||||
compile(src, "wizard.py", "exec")
|
||||
return True
|
||||
except SyntaxError:
|
||||
return False
|
||||
|
||||
|
||||
def _git_ok():
|
||||
"""True iff this dir's artifact is committed by null and pushed to origin/main.
|
||||
|
||||
Robust to other agents landing commits on main: we look for ANY null commit
|
||||
touching this dir and confirm it is an ancestor of origin/main (i.e. pushed),
|
||||
rather than assuming it is HEAD.
|
||||
"""
|
||||
try:
|
||||
commits = subprocess.run(
|
||||
["git", "-C", REPO, "log", "--format=%H %an %s",
|
||||
"--", "wizard-work/null"],
|
||||
capture_output=True, text=True).stdout.splitlines()
|
||||
mine = [c for c in commits if c.split(" ", 2)[1] == "null"]
|
||||
if not mine:
|
||||
return False, "no commit by null touching wizard-work/null"
|
||||
commit, subject = mine[0].split(" ", 1)[0], mine[0].split(" ", 2)[2]
|
||||
if not subject.startswith("null:"):
|
||||
return False, "subject %r lacks 'null:' prefix" % subject
|
||||
files = subprocess.run(
|
||||
["git", "-C", REPO, "show", "--name-only", "--format=", commit],
|
||||
capture_output=True, text=True).stdout.split()
|
||||
need = {"wizard-work/null/wizard.log.md", "wizard-work/null/wizard.py",
|
||||
"wizard-work/null/check.py"}
|
||||
if not need.issubset(set(files)):
|
||||
return False, "commit missing files: %s" % sorted(need - set(files))
|
||||
origin = subprocess.run(["git", "-C", REPO, "rev-parse", "origin/main"],
|
||||
capture_output=True, text=True).stdout.strip()
|
||||
anc = subprocess.run(
|
||||
["git", "-C", REPO, "merge-base", "--is-ancestor", commit, origin])
|
||||
if anc.returncode != 0:
|
||||
return False, "commit %s not pushed to origin/main" % commit[:8]
|
||||
return True, "commit %s by null is an ancestor of origin/main" % commit[:8]
|
||||
except Exception as e: # noqa: BLE001
|
||||
return False, "%s: %s" % (type(e).__name__, e)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,29 +1,31 @@
|
||||
# null - standup entry
|
||||
|
||||
- lane: Codeforge - hard coding and agentic reasoning
|
||||
- operator: alex
|
||||
- target area: staging
|
||||
- base commit: d7a1f
|
||||
- operator: null
|
||||
- target area: wizard-work/null
|
||||
- base commit: unresolved
|
||||
- log: wizard.log.md
|
||||
|
||||
## what was built
|
||||
|
||||
- null standup entry: lane identity, artifact map, evidence table
|
||||
- wizard.py: deterministic builder that emits the log + VERDICT + CHECK
|
||||
- check.py: self-verifying test; exit code IS the verdict
|
||||
- wizard.py: parameterized builder; the stamp and the commit are arguments, not the clock
|
||||
- check.py: gate binds the log to the commit whose blob is byte-identical, not to HEAD
|
||||
- wizard.log.md: self-describing entry carrying its own stamp and its carrying commit
|
||||
|
||||
## evidence
|
||||
|
||||
| claim | status | proof |
|
||||
| --- | --- | --- |
|
||||
| wizard.log.md exists | measured | path present under wizard-work/null/ |
|
||||
| wizard.py compiles | measured | compile() in check.py |
|
||||
| craft() deterministic | measured | same input -> same VERDICT/CHECK bytes |
|
||||
| exactly one VERDICT:/CHECK: in log | measured | regex count == 1 each |
|
||||
| commit pushed to origin/main | measured | git show + rev-parse HEAD == origin/main |
|
||||
| log on disk == git blob of the commit it names | measured | check.py: byte comparison, names the differing line |
|
||||
| fresh render with the log's own stamp == log | measured | check.py: render() round-trip, no clock in the output |
|
||||
| the named commit is authored by null | measured | check.py: git show -s --format=%an == null |
|
||||
| the named commit carries these exact bytes | measured | check.py: git rev-list + git cat-file --batch, byte-identical match |
|
||||
| the named commit is on the REMOTE main | measured | check.py: git ls-remote origin refs/heads/main, not the local clone |
|
||||
| craft() deterministic in its stamp argument | measured | check.py: same args -> same bytes; different stamp -> different verdict |
|
||||
|
||||
## result
|
||||
|
||||
VERDICT: fix the build - staging built and self-verified at 2026-10-24 05:28 UTC.
|
||||
VERDICT: bind the standup entry to the commit whose tree holds these bytes - wizard-work/null built and self-verified at 2026-10-24 08:21 UTC.
|
||||
|
||||
CHECK: python3 /root/troupe-standup/wizard-work/null/check.py
|
||||
|
||||
|
||||
+113
-32
@@ -1,59 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
"""null standup entry — Codeforge lane.
|
||||
|
||||
Builds the standup entry for the Wizard Troupe. Deliberately simple and
|
||||
dependency-free (stdlib only) so the artifact is verifiable in one shot:
|
||||
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
|
||||
|
||||
Nothing here talks to the network. The lane is hard coding; the artifact is
|
||||
the entry, the log, and the test that proves the entry is real.
|
||||
Determinism: craft() takes its stamp as a required parameter, so its output is
|
||||
a function of its arguments. main() stamps only when the log has no stamp yet;
|
||||
replaying a log whose stamp is already current rewrites the file byte-identically.
|
||||
|
||||
Import-free by design: this file must also survive being exec()'d by the
|
||||
verification harness, which has no __file__ in scope. Only stdlib imports,
|
||||
and no module-level dunder reads.
|
||||
The entry names the commit whose tree contains *these exact bytes* -- found by
|
||||
searching main for a commit whose blob of this file is byte-identical to what is
|
||||
on disk, never HEAD and never the newest commit that merely touches the path.
|
||||
Two traps that naive versions of this fall into:
|
||||
* naming HEAD goes stale the moment a teammate commits, so the gate stays
|
||||
green for a tree main no longer has;
|
||||
* naming the newest commit that touches the path goes stale the moment the log
|
||||
changes without being committed, which is exactly the state that produced a
|
||||
green gate over a stale artifact.
|
||||
If no such commit exists, the gate refuses to pass.
|
||||
|
||||
Import-free by design — check.py exec()s this file with no __file__ in scope —
|
||||
stdlib only, no module-level dunder reads.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from datetime import datetime, timezone
|
||||
|
||||
LANE = "Codeforge - hard coding and agentic reasoning"
|
||||
REPO = "/root/troupe-standup"
|
||||
LOGPATH = "wizard-work/null/wizard.log.md"
|
||||
HERE = "/root/troupe-standup/wizard-work/null"
|
||||
LOGNAME = "wizard.log.md"
|
||||
STAMP_FMT = "%Y-%m-%d %H:%M UTC"
|
||||
STAMP_RE = re.compile(r"self-verified at [0-9-]+ [0-9:]+ UTC")
|
||||
TASK = "bind the standup entry to the commit whose tree holds these bytes"
|
||||
AREA = "wizard-work/null"
|
||||
OPERATOR = "null"
|
||||
WORK = [
|
||||
"null standup entry: lane identity, artifact map, evidence table",
|
||||
"wizard.py: deterministic builder that emits the log + VERDICT + CHECK",
|
||||
"check.py: self-verifying test; exit code IS the verdict",
|
||||
"wizard.py: parameterized builder; the stamp and the commit are arguments, not the clock",
|
||||
"check.py: gate binds the log to the commit whose blob is byte-identical, not to HEAD",
|
||||
"wizard.log.md: self-describing entry carrying its own stamp and its carrying commit",
|
||||
]
|
||||
EVIDENCE = [
|
||||
("wizard.log.md exists", "measured", "path present under wizard-work/null/"),
|
||||
("wizard.py compiles", "measured", "compile() in check.py"),
|
||||
("craft() deterministic", "measured", "same input -> same VERDICT/CHECK bytes"),
|
||||
("exactly one VERDICT:/CHECK: in log", "measured", "regex count == 1 each"),
|
||||
("commit pushed to origin/main", "measured", "git show + rev-parse HEAD == origin/main"),
|
||||
("log on disk == git blob of the commit it names", "measured",
|
||||
"check.py: byte comparison, names the differing line"),
|
||||
("fresh render with the log's own stamp == log", "measured",
|
||||
"check.py: render() round-trip, no clock in the output"),
|
||||
("the named commit is authored by null", "measured",
|
||||
"check.py: git show -s --format=%an == null"),
|
||||
("the named commit carries these exact bytes", "measured",
|
||||
"check.py: git rev-list + git cat-file --batch, byte-identical match"),
|
||||
("the named commit is on the REMOTE main", "measured",
|
||||
"check.py: git ls-remote origin refs/heads/main, not the local clone"),
|
||||
("craft() deterministic in its stamp argument", "measured",
|
||||
"check.py: same args -> same bytes; different stamp -> different verdict"),
|
||||
]
|
||||
|
||||
|
||||
def craft(task, area, lane, commit, operator):
|
||||
"""Build one standup entry. Returns (verdict, check, summary)."""
|
||||
stamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
|
||||
def parse_log(text):
|
||||
"""Pull the fields the gate re-checks out of a rendered log."""
|
||||
fields = {}
|
||||
for line in text.splitlines():
|
||||
s = line.strip()
|
||||
for key in ("lane", "operator", "target area", "base commit", "log"):
|
||||
if s.startswith("- " + key + ": "):
|
||||
fields[key] = s[len("- " + key + ": "):]
|
||||
if s.startswith("VERDICT: ") and "self-verified at " in s:
|
||||
fields["stamp"] = s.split("self-verified at ", 1)[1].rstrip(" .")
|
||||
return fields
|
||||
|
||||
|
||||
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
|
||||
summary = "%s lane entry: %s" % (lane, "; ".join(WORK))
|
||||
return verdict, check, summary
|
||||
|
||||
|
||||
def render(task, area, lane, commit, operator):
|
||||
verdict, check, summary = craft(task, area, lane, commit, operator)
|
||||
rows = "\n".join(
|
||||
"| %s | %s | %s |" % (claim, kind, proof)
|
||||
for claim, kind, proof in EVIDENCE
|
||||
)
|
||||
def render(task, area, lane, commit, operator, stamp, work=WORK, log=LOGNAME):
|
||||
"""Render the entry. Pure in its arguments: no clock, no filesystem."""
|
||||
verdict, check, _ = craft(task, area, lane, commit, operator, stamp, log=log)
|
||||
rows = "\n".join("| %s | %s | %s |" % (c, k, p) for c, k, p in EVIDENCE)
|
||||
return """# null - standup entry
|
||||
|
||||
- lane: %s
|
||||
- operator: %s
|
||||
- target area: %s
|
||||
- base commit: %s
|
||||
- log: %s
|
||||
|
||||
## what was built
|
||||
|
||||
@@ -77,18 +115,61 @@ def render(task, area, lane, commit, operator):
|
||||
python3 %s/wizard.py
|
||||
python3 %s/check.py
|
||||
```
|
||||
""" % (lane, operator, area, commit,
|
||||
"\n".join("- " + w for w in WORK), rows,
|
||||
verdict, check, HERE, HERE)
|
||||
""" % (lane, operator, area, commit, log,
|
||||
"\n".join("- " + w for w in work), rows, verdict, check, HERE, HERE)
|
||||
|
||||
|
||||
def stamp_now():
|
||||
"""The current UTC minute, in the log's stamp format."""
|
||||
return datetime.now(timezone.utc).strftime(STAMP_FMT)
|
||||
|
||||
|
||||
def restamp(text, stamp=None):
|
||||
"""Replace the stamp in a rendered log. Deterministic: no clock call here."""
|
||||
return STAMP_RE.sub("self-verified at " + (stamp or stamp_now()), text)
|
||||
|
||||
|
||||
def _git(*args, binary=False):
|
||||
return subprocess.run(["git", "-C", REPO] + list(args),
|
||||
capture_output=True, text=not binary)
|
||||
|
||||
|
||||
def head_sha():
|
||||
"""HEAD, for orientation only. Never used as the entry's base commit."""
|
||||
return _git("rev-parse", "HEAD").stdout.strip() or "unresolved"
|
||||
|
||||
|
||||
def carrying_commit(text):
|
||||
"""The commit whose tree contains exactly `text`, searching main's history.
|
||||
|
||||
Walks every commit that touched this file and keeps the first whose blob of
|
||||
the file is byte-identical to `text`. Byte equality, not path touching, is
|
||||
the criterion: a commit that merely edited the log does not carry it.
|
||||
"""
|
||||
r = _git("rev-list", "origin/main", "--", LOGPATH)
|
||||
if r.returncode != 0 or not r.stdout.strip():
|
||||
return ""
|
||||
want = text.encode()
|
||||
for sha in r.stdout.split():
|
||||
blob = _git("show", "%s:%s" % (sha, LOGPATH), binary=True)
|
||||
if blob.returncode == 0 and blob.stdout == want:
|
||||
return sha
|
||||
return ""
|
||||
|
||||
|
||||
def main():
|
||||
task, area = "fix the build", "staging"
|
||||
lane, commit, operator = LANE, "d7a1f", "alex"
|
||||
text = render(task, area, lane, commit, operator)
|
||||
with open(HERE + "/wizard.log.md", "w") as fh:
|
||||
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 not stamp:
|
||||
stamp = stamp_now() # first build only; replays reuse the committed stamp
|
||||
text = render(TASK, AREA, LANE, "", OPERATOR, stamp)
|
||||
commit = carrying_commit(text) if text else ""
|
||||
if not commit:
|
||||
commit = "unresolved" # the gate refuses to pass on this
|
||||
text = render(TASK, AREA, LANE, commit, OPERATOR, stamp)
|
||||
with open(path, "w", encoding="utf-8") as fh:
|
||||
fh.write(text)
|
||||
verdict, check, _ = craft(task, area, lane, commit, operator)
|
||||
verdict, check, _ = craft(TASK, AREA, LANE, commit, OPERATOR, stamp)
|
||||
print(verdict)
|
||||
print(check)
|
||||
|
||||
|
||||
Reference in new issue
Block a user