Files
troupe-standup/wizard-work/ledger/verify_checkin_census.py
T

84 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""Independent re-derivation of the check-in census for 2026-11-05.
Verifies the committed CSV under wizard-work/ledger/ against a from-scratch
re-derivation of `git ls-tree` at HEAD. Exit 0 iff identical; 1 otherwise.
"""
import argparse
import csv
import os
import subprocess
import sys
CSV_NAME = "2026-11-05-checkin-census.csv"
def git(repo, *args):
return subprocess.run(
["git", "-C", repo] + list(args), check=True, capture_output=True, text=True
).stdout
def rederive(repo):
"""Return sorted [(date, wizard, path, size, sha)] straight from git."""
names = git(repo, "ls-tree", "-r", "--name-only", "HEAD").splitlines()
longs = git(repo, "ls-tree", "-r", "-l", "HEAD").splitlines()
big = {}
for ln in longs:
tab = ln.find("\t")
head, path = ln[:tab], ln[tab + 1:]
tok = head.split()
big[path] = (int(tok[3]), tok[2])
rows = []
for p in names:
if not p.startswith("checkins/") or p == "checkins/README.md":
continue
rel = p[len("checkins/"):]
rows.append((rel[:10], rel[11:-3], p, big[p][0], big[p][1]))
rows.sort()
return rows
def read_committed(repo):
path = os.path.join(repo, "wizard-work", "ledger", CSV_NAME)
with open(path, newline="") as f:
return list(csv.reader(f))
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--check", action="store_true", help="run the verification")
ap.add_argument("--repo", default="/root/troupe-standup")
args = ap.parse_args()
if not args.check:
return 0
repo = args.repo
committed = read_committed(repo)
expected = [[str(s) for s in r] for r in rederive(repo)]
ok = True
if len(committed) - 1 != len(expected):
ok = False
print("ROW COUNT MISMATCH: committed=%d expected=%d"
% (len(committed) - 1, len(expected)))
got = committed[1:]
for i in range(max(len(got), len(expected))):
a = got[i] if i < len(got) else None
b = expected[i] if i < len(expected) else None
if a != b:
ok = False
print("DIFF line %d: committed=%r expected=%r" % (i + 2, a, b))
dates = sorted({r[0] for r in rederive(repo)})
wizards = sorted({r[1] for r in rederive(repo)})
print("checkin census: rows=%d dates=%d wizards=%d"
% (len(expected), len(dates), len(wizards)))
print("check commit tree: HEAD -> %s" % git(repo, "rev-parse", "HEAD").strip()[:12])
sys.exit(0 if ok else 1)
if __name__ == "__main__":
main()