Files
troupe-standup/wizard-work/ledger/2026-10-29-checkin-census/gen.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

175 lines
6.6 KiB
Python

#!/usr/bin/env python3
"""Generator: check-in signee census, derived from a PINNED revision.
Extracts every date-tagged check-in file at `<pin>:checkins/`, resolving the
signee handle, the committer, and the headline, then emits a table (CSV/JSON/MD).
Evidence source: `git ls-tree <pin> -- checkins/` (the authoritative file list at
that revision) and `git log -1 <pin> --format=... -- <file>` (the committer of
the last commit touching the file at that revision). Nothing is invented: every
row is derived from a real blob and a real git object, and no host path is read
or written -- the first version hardcoded `/root/troupe-standup` for both ROOT
and OUT and walked `git ls-files`, which is the working tree, not a commit.
The scope is the revision, so this generator is reproducible: run at the pin
that carries the committed tables (`b21bb10`), it rewrites them byte for byte.
It writes nothing without `--write`.
Usage:
gen.py --pin b21bb10 # dry run: row counts only
gen.py --pin b21bb10 --write # publish into this artifact's directory
gen.py --pin b21bb10 --outdir DIR --write
Exit: 0 derived/published, 1 the pin cannot be read, 2 bad arguments.
"""
import argparse
import csv
import json
import re
import subprocess
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
DATE = re.compile(r"^checkins/(\d{4}-\d{2}-\d{2})-(.+)$")
INDEX_FILE = "checkins/README.md"
TAG = "2026-10-29"
def repo_root():
try:
out = subprocess.run(["git", "-C", str(HERE), "rev-parse", "--show-toplevel"],
capture_output=True, text=True, timeout=60)
if out.returncode == 0 and out.stdout.strip():
return Path(out.stdout.strip())
except (OSError, subprocess.SubprocessError):
pass
return HERE.parent.parent.parent
def run_git(repo, args, binary=False):
out = subprocess.run(["git", "-C", str(repo)] + args,
capture_output=True, text=not binary, timeout=120)
if out.returncode != 0:
err = out.stderr if not binary else (out.stderr or b"").decode("utf-8", "replace")
raise RuntimeError("git %s failed: %s" % (" ".join(args), (err or "").strip()))
return out.stdout
def pinned_checkin_files(repo, rev):
out = run_git(repo, ["ls-tree", "-r", "--name-only", rev, "--", "checkins/"])
return sorted(f for f in out.splitlines() if f.endswith(".md"))
def signee_from_filename(name):
m = DATE.match(name)
token = m.group(2)
token = token[:-3] if token.endswith(".md") else token
return re.sub(r"-\d+$", "", token) # drop -02/-03 revision markers
def headline(repo, rev, path):
text = run_git(repo, ["show", "%s:%s" % (rev, path)], binary=True)
for line in text.decode("utf-8", "replace").split("\n"):
line = line.rstrip("\r")
if line.startswith("# "):
return line[2:].strip()
return ""
def committer(repo, rev, path):
out = run_git(repo, ["log", "-1", "--format=%an <%ae>", rev, "--", path]).strip()
return out or "(no committer)"
def derive(repo, rev):
rows = []
for f in pinned_checkin_files(repo, rev):
if f == INDEX_FILE:
rows.append({
"file": INDEX_FILE,
"date": TAG,
"signee": "troupe-pipe (index)",
"headline": "Check-ins index",
"committer": "(index file; no committer)",
"kind": "index",
})
continue
m = DATE.match(f)
rows.append({
"file": f,
"date": m.group(1),
"signee": signee_from_filename(f),
"headline": headline(repo, rev, f),
"committer": committer(repo, rev, f),
"kind": "checkin",
})
rows.sort(key=lambda r: (r["date"], r["file"]))
return rows
def write_outputs(out_dir, rows):
out_dir.mkdir(parents=True, exist_ok=True)
csv_path = out_dir / "checkin-census.csv"
with open(csv_path, "w", newline="", encoding="utf-8") as fh:
w = csv.DictWriter(fh, fieldnames=["file", "date", "signee", "headline",
"committer", "kind"])
w.writeheader()
for r in rows:
w.writerow(r)
json_path = out_dir / "checkin-census.json"
with open(json_path, "w", encoding="utf-8") as fh:
json.dump({
"source": "git ls-files checkins/ (authoritative tracked list)",
"total_checkin_rows": len([r for r in rows if r["kind"] == "checkin"]),
"rows": rows,
}, fh, indent=2, ensure_ascii=False)
md_path = out_dir / "checkin-census.md"
with open(md_path, "w", encoding="utf-8") as fh:
fh.write("# Check-in signee census (%s)\n\n" % TAG)
fh.write("Source: `git ls-files checkins/`. Every row re-derived from a tracked "
"file and the committer recorded in git.\n\n")
fh.write("| file | date | signee | headline | committer | kind |\n")
fh.write("|---|---|---|---|---|---|\n")
for r in rows:
fh.write(f"| {r['file']} | {r['date']} | {r['signee']} | {r['headline']} | "
f"{r['committer']} | {r['kind']} |\n")
return csv_path, json_path, md_path
def main(argv=None):
ap = argparse.ArgumentParser(description="derive the check-in signee census "
"from a pinned git revision")
ap.add_argument("--pin", required=True, help="revision whose checkins/ is the scope")
ap.add_argument("--outdir", default=None,
help="directory to write into (default: this artifact's directory)")
ap.add_argument("--write", action="store_true",
help="publish; without it the run only derives and reports")
args = ap.parse_args(argv)
repo = repo_root()
try:
rev = run_git(repo, ["rev-parse", "--verify", args.pin + "^{commit}"]).strip()
rows = derive(repo, rev)
except RuntimeError as exc:
print("VALIDATION_FAILED: %s" % exc, file=sys.stderr)
return 1
except (OSError, subprocess.SubprocessError, ValueError, AttributeError) as exc:
print("CANNOT GRADE: %s: %s" % (type(exc).__name__, exc), file=sys.stderr)
return 2
dated = len([r for r in rows if r["kind"] == "checkin"])
print("pin=%s rows=%d dated=%d index=%d" % (rev[:12], len(rows), dated, len(rows) - dated))
if not args.write:
print("dry run: nothing written (pass --write to publish)")
return 0
out = Path(args.outdir) if args.outdir else HERE
for p in write_outputs(out, rows):
print("wrote:", p)
return 0
if __name__ == "__main__":
sys.exit(main())