#!/usr/bin/env python3 """Grade the 2026-10-29 check-in signee census against its PINNED revision. WHAT IT GRADES -- five legs, every one re-derived from `git ls-tree` / `git show` / `git log` at the pinned commit, compared against the committed tables. Nothing is read from the working tree (so tomorrow's check-in cannot red this artifact) and nothing is written (the previous revision's legs ran against `git ls-files`, which is the live index, and its row set grew with the archive). 1 scope the pin file beside this script: header, sortedness, uniqueness, names 2 pin the dated 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 csv every cell of the committed CSV against the re-derivation, plus the `checkins/README.md` index row and the header order 4 md the MD's table block, row for row, against the same derivation 5 json the JSON's rows and `total_checkin_rows` EXIT CODES: 0 every leg passed; 1 a fault (including "the pin is not a usable input"); 2 cannot grade at all (no git). 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-29-checkin-census.files" TAG = "2026-10-29" CSV_PATH = HERE / "checkin-census.csv" MD_PATH = HERE / "checkin-census.md" JSON_PATH = HERE / "checkin-census.json" INDEX_FILE = "checkins/README.md" FIELDS = ["file", "date", "signee", "headline", "committer", "kind"] NAME_RE = re.compile(r"^(\d{4}-\d{2}-\d{2})-(.+)\.md$") PIN_RE = re.compile(r"^# pin checkins@([0-9a-f]{40}) tree=([0-9a-f]{40})$") 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 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 = PIN_RE.match(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 dated name(s) == checkins/ tree %s at %s" % ( len(names), tree[:12], sha[:7]) def derive(repo, sha, names): """Rows in the artifact's order: (date, file), plus the README index row.""" rows = [] for name in names: path = "checkins/" + name m = NAME_RE.match(name) signee = re.sub(r"-\d+$", "", m.group(2)) text = git(repo, "show", "%s:%s" % (sha, path)).decode("utf-8", "replace") head = "" for line in text.split("\n"): if line.startswith("# "): head = line[2:].strip() break who = git(repo, "log", "-1", "--format=%an <%ae>", sha, "--", path).decode().strip() rows.append({"file": path, "date": m.group(1), "signee": signee, "headline": head, "committer": who or "(no committer)", "kind": "checkin"}) tracked = git(repo, "ls-tree", "-r", "--name-only", sha, "--", "checkins/").decode() if INDEX_FILE in tracked.splitlines(): rows.append({"file": INDEX_FILE, "date": TAG, "signee": "troupe-pipe (index)", "headline": "Check-ins index", "committer": "(index file; no committer)", "kind": "index"}) rows.sort(key=lambda r: (r["date"], r["file"])) return rows def leg_csv(rows): with open(CSV_PATH, encoding="utf-8", newline="") as fh: reader = csv.reader(fh) header = next(reader) got = list(reader) if header != FIELDS: raise Fault("CSV header %r != %r" % (header, FIELDS)) want = [[r[f] for f in FIELDS] for r in rows] if len(got) != len(want): raise Fault("CSV 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("CSV row %d: %r != pin %r" % (i, g, w)) return "PASS csv: %d row(s) match the pin cell for cell" % len(got) def md_rows(text): out, inside = [], False for line in text.splitlines(): if not line.startswith("|"): if inside: break continue cells = [c.strip() for c in line.strip().strip("|").split("|")] if not inside: inside = cells == FIELDS continue if set("".join(cells)) <= set("-: "): continue out.append(cells) return out def leg_md(rows): got = md_rows(MD_PATH.read_text(encoding="utf-8")) want = [[r[f] for f in FIELDS] 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("MD table: %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: %d row(s) match the pin" % len(got) def leg_json(rows): doc = json.loads(JSON_PATH.read_text(encoding="utf-8")) got = [{f: r.get(f) for f in FIELDS} for r in doc.get("rows", [])] want = [{f: r[f] for f in FIELDS} 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)) n_dated = len([r for r in rows if r["kind"] == "checkin"]) if doc.get("total_checkin_rows") != n_dated: raise Fault("JSON total_checkin_rows %r != %d derived" % ( doc.get("total_checkin_rows"), n_dated)) return "PASS json: %d row(s), total_checkin_rows=%d, match the pin" % (len(got), n_dated) def main(argv=None): ap = argparse.ArgumentParser(description="grade the 2026-10-29 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) lines.append(leg_csv(rows)) lines.append(leg_md(rows)) lines.append(leg_json(rows)) 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 dated=%d pin=%s" % (TAG, len(rows), len(rows) - 1, sha[:7])) return 0 if __name__ == "__main__": sys.exit(main())