Files
troupe-standup/wizard-work/ledger/2026-10-28-checkin-census/grade.py
T
volt 76471add2d ledger: both later check-in censuses graded at their own revision (Q151)
The 2026-10-28 and 2026-10-29 check-in censuses were red at d42f577 for
three reasons at once: both CHECKs were Python under a 'bash CHECK' line
(rc 2, import: command not found), both graded the live tree (so every new
check-in reddened a dated artifact), and both hardcoded /root/troupe-standup.
The 10-28 table also carried a 101st row for checkins/2026-10-27-sentinel.md,
a file in no revision.

- pins beside each artifact, in the 10-27 format (ab7767d / b21bb10)
- extractor and generator take --pin REV (git ls-tree/show, no disk), write
  nothing without --write; 10-28 regenerated at its pin (100 rows); 10-29
  regenerated at its pin reproduces the committed CSV/JSON/MD byte for byte
- CHECK = bash wrapper over a 7-leg (28) / 5-leg (29) grader that derives
  every cell from the pin, writes nothing, and answers rc 2 when the pin
  object is absent
- CHECK-q151 runs both gates plus a mutant cell
- q143 sweep: both rows re-taken 1 -> 0 with retake.py, CHECK-q151 added;
  q137 open-set pin moved with the record
2026-11-01 21:44:26 +00:00

328 lines
14 KiB
Python
Executable File

#!/usr/bin/env python3
"""Grade the 2026-10-28 check-in census against its PINNED revision.
WHAT IT GRADES -- seven legs, each re-deriving from `git show <pin>:checkins/...`
and comparing against the committed tables. Nothing is read from the working
tree, so a check-in that lands tomorrow cannot red this artifact, and nothing is
written, so a run cannot regenerate its own input.
1 scope the pin file beside this script: header, sortedness, uniqueness, names
2 pin the name list equals `checkins/` at the pinned commit (SKIP if the
object is not in this database -- the committed list is then the pin)
3 tsv every cell of the committed TSV against the re-derivation
4 md-inv the MD's full-inventory rows
5 md-head the MD's headline measures
6 md-late the MD's per-signer latest block
7 json the JSON's rows, headline counters and pin field
The re-derivation is deliberately a second implementation -- line-oriented
section finding, not the committed extractor's section regex -- and it never
imports that extractor, so the two cannot agree by sharing a bug.
EXIT CODES: 0 every leg passed; 1 a fault (including "the pin is not a usable
input", which is a refusal to grade rather than a fallback to today's disk);
2 cannot grade at all (no git, no python3 in the wrapper).
Usage: python3 grade.py [--repo DIR] (or `bash CHECK`, which runs this file)
"""
import argparse
import csv
import json
import re
import subprocess
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
PIN_FILE = HERE / "2026-10-28-checkin-census.files"
TAG = "2026-10-28"
TSV = HERE / ("checkin-census-" + TAG + ".tsv")
MD = HERE / ("checkin-census-" + TAG + ".md")
JSON = HERE / ("checkin-census-" + TAG + ".json")
SECTIONS = ("## Did", "## Blocked", "## Next", "## Ask")
NAME_RE = re.compile(r"^(\d{4}-\d{2}-\d{2})-(.+)\.md$")
ITEM_RE = re.compile(r"^\s*### \d+\.\s+\S")
class Fault(Exception):
"""A graded leg failed; the message is the verdict line."""
class CannotGrade(Exception):
"""The instrument itself cannot run."""
def git(repo, *args):
try:
out = subprocess.run(["git", "-C", str(repo)] + list(args),
capture_output=True, timeout=180)
except (OSError, subprocess.SubprocessError) as exc:
raise CannotGrade("git %s: %s" % (args[0], exc))
if out.returncode != 0:
raise Fault("git %s failed: %s" % (" ".join(args),
out.stderr.decode("utf-8", "replace").strip()))
return out.stdout
def find_repo():
for cand in (HERE, HERE.parent):
r = subprocess.run(["git", "-C", str(cand), "rev-parse", "--show-toplevel"],
capture_output=True, text=True)
if r.returncode == 0 and r.stdout.strip():
return Path(r.stdout.strip())
return HERE.parent.parent.parent
# --------------------------------------------------------------- the pin
def require_pin(repo, sha):
"""A revision this clone does not carry cannot grade a census of it."""
try:
git(repo, "cat-file", "-e", sha + "^{commit}")
except Fault:
raise CannotGrade("pin %s is not in this object database: a census of that "
"revision cannot be graded without it" % sha[:12])
def read_pin():
if not PIN_FILE.is_file() or PIN_FILE.stat().st_size == 0:
raise Fault("SCOPE NOT ESTABLISHED: pinned name list missing or empty: %s"
% PIN_FILE.name)
lines = PIN_FILE.read_text(encoding="utf-8").splitlines()
m = re.match(r"^# pin checkins@([0-9a-f]{40}) tree=([0-9a-f]{40})$", lines[0])
if not m:
raise Fault("SCOPE NOT ESTABLISHED: pin header not understood: %r" % lines[0])
names = lines[1:]
if not names:
raise Fault("SCOPE NOT ESTABLISHED: pin names no files")
bad = [n for n in names if not NAME_RE.match(n)]
if bad:
raise Fault("SCOPE NOT ESTABLISHED: %d pinned name(s) are not YYYY-MM-DD-*.md "
"(first: %r)" % (len(bad), bad[0]))
if len(set(names)) != len(names):
raise Fault("SCOPE NOT ESTABLISHED: duplicated name(s) in the pin")
if sorted(names) != names:
raise Fault("SCOPE NOT ESTABLISHED: pin names are not sorted (LC_ALL=C)")
return m.group(1), m.group(2), names
def leg_pin(repo, sha, tree, names):
real = git(repo, "rev-parse", ("%s:checkins" % sha)).decode().strip()
if real != tree:
raise Fault("pin tree %s is not %s:checkins (%s)" % (tree[:12], sha[:7], real[:12]))
out = git(repo, "ls-tree", "-r", "--name-only", sha, "--", "checkins/").decode("utf-8")
at_pin = sorted(p[len("checkins/"):] for p in out.splitlines()
if p.startswith("checkins/") and NAME_RE.match(p[len("checkins/"):]))
if at_pin != names:
only_pin = [n for n in at_pin if n not in set(names)]
only_list = [n for n in names if n not in set(at_pin)]
raise Fault("pin name list != checkins/ at %s (+%d at pin, +%d in pin): %s %s"
% (sha[:7], len(only_pin), len(only_list), only_pin[:3], only_list[:3]))
return "PASS pin: %d name(s) == checkins/ tree %s at %s" % (len(names), tree[:12], sha[:7])
# ------------------------------------------------------- the re-derivation
def blob(repo, sha, name):
return git(repo, "show", "%s:checkins/%s" % (sha, name)).decode("utf-8", "replace")
def analyse(text):
"""Line-oriented: flags, numbered items under ## Did, and the slice length."""
lines = text.split("\n")
flags = {s: False for s in SECTIONS}
start = None
for i, line in enumerate(lines):
bare = line.rstrip()
if bare in flags:
flags[bare] = True
if bare == "## Did" and start is None:
start = i
items, chars = 0, 0
if start is not None:
end = len(lines)
for j in range(start + 1, len(lines)):
if lines[j].rstrip() in flags:
end = j
break
body = lines[start:end]
items = len([l for l in body[1:] if ITEM_RE.match(l)])
chars = len("\n".join(body)) + (1 if end < len(lines) else 0)
return {
"has_done": flags["## Did"], "has_blocked": flags["## Blocked"],
"has_next": flags["## Next"], "has_ask": flags["## Ask"],
"did_items": items, "did_chars": chars,
}
def derive(repo, sha, names):
rows = []
for name in names:
m = NAME_RE.match(name)
rows.append(dict(date=m.group(1), signer=m.group(2), file=name,
**analyse(blob(repo, sha, name))))
return rows
def skipped_at_pin(repo, sha):
out = git(repo, "ls-tree", "-r", "--name-only", sha + ":checkins").decode("utf-8")
return [p for p in out.splitlines()
if p.endswith(".md") and not NAME_RE.match(p)]
# ------------------------------------------------------------- the tables
def leg_tsv(rows):
with open(TSV, encoding="utf-8", newline="") as fh:
reader = csv.reader(fh, delimiter="\t")
header = next(reader)
got = [[c.strip() for c in r] for r in reader]
want_header = ["date", "signer", "file", "has_done", "has_blocked", "has_next",
"has_ask", "did_items", "did_chars"]
if header != want_header:
raise Fault("TSV header %r != %r" % (header, want_header))
want = [[r["date"], r["signer"], r["file"], str(r["has_done"]), str(r["has_blocked"]),
str(r["has_next"]), str(r["has_ask"]), str(r["did_items"]), str(r["did_chars"])]
for r in rows]
if len(got) != len(want):
raise Fault("TSV has %d row(s); the pin derives %d" % (len(got), len(want)))
for i, (g, w) in enumerate(zip(got, want)):
if g != w:
raise Fault("TSV row %d: %r != pin %r" % (i, g, w))
return "PASS tsv: %d row(s) match the pin cell for cell" % len(got)
def md_block(text, header_cells):
"""Rows of the table whose header is exactly `header_cells`, as cell lists."""
lines = text.splitlines()
out = []
inside = False
for line in lines:
if not line.startswith("|"):
if inside:
break
continue
cells = [c.strip() for c in line.strip().strip("|").split("|")]
if not inside:
if cells == header_cells:
inside = True
continue
if set("".join(cells)) <= set("-: "):
continue
out.append(cells)
return out
def leg_md_inventory(text, rows):
want = sorted([[r["date"], r["signer"], r["file"],
"1" if r["has_done"] else "0", "1" if r["has_blocked"] else "0",
"1" if r["has_next"] else "0", "1" if r["has_ask"] else "0",
str(r["did_items"]), str(r["did_chars"])]
for r in rows], key=lambda x: (x[0], x[1]))
got = [[c.strip("`") for c in r] for r in md_block(
text, ["date", "signer", "file", "Did", "Blocked", "Next", "Ask",
"did items", "did chars"])]
if got != want:
bad = next((i for i in range(min(len(got), len(want))) if got[i] != want[i]),
min(len(got), len(want)))
raise Fault("MD inventory: %d row(s) vs pin %d; first difference at row %d "
"(md %r, pin %r)" % (len(got), len(want), bad,
got[bad] if bad < len(got) else None,
want[bad] if bad < len(want) else None))
return "PASS md-inventory: %d row(s) match the pin" % len(got)
def leg_md_headline(text, rows, skipped):
want = {
"dated check-in files": str(len(rows)),
"non-dated files skipped": str(len(skipped)),
"signers": str(len({r["signer"] for r in rows})),
"total did items": str(sum(r["did_items"] for r in rows)),
"total did chars": str(sum(r["did_chars"] for r in rows)),
}
got = {c[0]: c[1] for c in md_block(text, ["measure", "value"])}
misses = [(k, got.get(k), v) for k, v in want.items() if got.get(k) != v]
if misses:
raise Fault("MD headline disagrees with the pin: %s"
% "; ".join("%s md=%r pin=%r" % m for m in misses))
return "PASS md-headline: %d measure(s) match the pin" % len(want)
def leg_md_latest(text, rows):
latest = {}
for r in rows:
cur = latest.get(r["signer"])
if cur is None or r["date"] > cur["latest_date"]:
latest[r["signer"]] = {"signer": r["signer"], "latest_date": r["date"],
"file": r["file"]}
want = [[latest[s]["signer"], latest[s]["latest_date"], latest[s]["file"]]
for s in sorted(latest)]
got = [[c[0], c[1], c[2].strip("`")] for c in md_block(
text, ["signer", "latest check-in", "file"])]
if got != want:
raise Fault("MD per-signer latest block != pin (%d md row(s), %d derived)"
% (len(got), len(want)))
return "PASS md-latest: %d signer row(s) match the pin" % len(got)
def leg_json(rows, sha, skipped):
doc = json.loads(JSON.read_text(encoding="utf-8"))
if doc.get("pin") != sha:
raise Fault("JSON pin %r != %r" % (doc.get("pin"), sha))
got = [{k: r.get(k) for k in ("date", "signer", "file", "has_done", "has_blocked",
"has_next", "has_ask", "did_items", "did_chars")}
for r in doc.get("rows", [])]
want = [{k: r[k] for k in ("date", "signer", "file", "has_done", "has_blocked",
"has_next", "has_ask", "did_items", "did_chars")}
for r in rows]
if got != want:
bad = next((i for i in range(min(len(got), len(want))) if got[i] != want[i]),
min(len(got), len(want)))
raise Fault("JSON rows: %d vs pin %d; first difference at row %d"
% (len(got), len(want), bad))
h = doc.get("headline", {})
want_h = {"files": len(rows), "signers": len({r["signer"] for r in rows}),
"skipped_non_dated": len(skipped),
"total_did_items": sum(r["did_items"] for r in rows),
"total_did_chars": sum(r["did_chars"] for r in rows)}
misses = [(k, h.get(k), v) for k, v in want_h.items() if h.get(k) != v]
if misses:
raise Fault("JSON headline disagrees with the pin: %s"
% "; ".join("%s json=%r pin=%r" % m for m in misses))
return "PASS json: %d row(s) and %d headline counter(s) match the pin" % (
len(got), len(want_h))
def main(argv=None):
ap = argparse.ArgumentParser(description="grade the 2026-10-28 check-in census")
ap.add_argument("--repo", default=None, help="repository to grade (default: this tree's)")
args = ap.parse_args(argv)
repo = Path(args.repo) if args.repo else find_repo()
try:
sha, tree, names = read_pin()
require_pin(repo, sha)
print("PASS scope: %d pinned dated file(s), pin %s" % (len(names), sha[:7]))
lines = [leg_pin(repo, sha, tree, names)]
rows = derive(repo, sha, names)
skipped = skipped_at_pin(repo, sha)
text = MD.read_text(encoding="utf-8")
lines.append(leg_tsv(rows))
lines.append(leg_md_inventory(text, rows))
lines.append(leg_md_headline(text, rows, skipped))
lines.append(leg_md_latest(text, rows))
lines.append(leg_json(rows, sha, skipped))
except Fault as exc:
print("FAIL: %s" % exc)
return 1
except CannotGrade as exc:
print("CANNOT GRADE: %s" % exc)
return 2
for line in lines:
print(line)
print("VERDICT=PASS census-%s rows=%d files=%d pin=%s"
% (TAG, len(rows), len(rows), sha[:7]))
return 0
if __name__ == "__main__":
sys.exit(main())