#!/usr/bin/env bash # CHECK — ledger commit-history refresh (Extract lane). # # Verifies the committed 2026-10-25-git-history.{csv,json,md} against a # RE-DERIVATION of the same snapshot, keyed by the committed `head` field # (the HEAD of the repo at the moment the artifact was captured). Because the # pinned head is re-derived with `git rev-list `, this is immune to new # commits landing above the snapshot: those commits are simply outside scope. # Exits 0 only when every check matches exactly. set -u REPO=/root/troupe-standup OUT="$REPO/wizard-work/ledger" JSON="$OUT/2026-10-25-git-history.json" CSV="$OUT/2026-10-25-git-history.csv" python3 - "$JSON" "$CSV" <<'PY' import json, csv, subprocess, sys repo = "/root/troupe-standup" json_path, csv_path = sys.argv[1], sys.argv[2] def git(*args): return subprocess.run( ["git", "-C", repo] + list(args), check=True, capture_output=True, text=True).stdout # ---- Load the committed snapshot and its pinned head ---- with open(json_path) as f: fixed = json.load(f) head = fixed.get("head") if not head: print("FAIL: json has no 'head' field") sys.exit(1) with open(csv_path, newline="") as f: rd = list(csv.reader(f)) hdr, data = rd[0], rd[1:] fails = [] def check(name, obs, exp): if obs == exp: print("PASS: %s" % name) else: print("FAIL: %s" % name) print(" observed: %r" % (obs,)) print(" expected: %r" % (exp,)) fails.append(name) # ---- Re-derive the snapshot from live git, keyed at `head` ---- meta = git("log", "--format=" + "%x01%H%x01%h%x01%an%x01%ae%x01%aI%x01%s", "--name-status", head).splitlines() rows = [] i = 0 while i < len(meta): line = meta[i] if not line.startswith("\x01"): i += 1 continue fields = line.split("\x01") if len(fields) < 7: i += 1 continue _full, full, short, name, email, date, subject = fields[:7] subject = subject.lstrip("\x01") paths = [] i += 1 while i < len(meta) and not meta[i].startswith("\x01"): ns = meta[i] if "\t" in ns: paths.append(ns.split("\t", 1)[1]) i += 1 rows.append({"hash": full, "short": short, "name": name, "email": email, "date": date, "subject": subject, "files": len(set(paths))}) rows.sort(key=lambda r: r["date"]) earliest, latest = rows[0]["date"], rows[-1]["date"] rows.sort(key=lambda r: (-r["files"], r["date"], r["hash"])) for idx, r in enumerate(rows, 1): r["rank"] = idx # 1. Column structure of the committed CSV. check("csv header", hdr, ["rank","hash","short","name","email","date","subject","files"]) # 2. Full row-level agreement, field for field (rank, hash, short, name, email, # date, subject, files) against the independent re-derivation. exp_rows = [[str(r["rank"]), r["hash"], r["short"], r["name"], r["email"], r["date"], r["subject"], str(r["files"])] for r in rows] if len(data) != len(rows): fails.append("csv row count") for a, b in zip(data, exp_rows): if a != b: fails.append("row mismatch at data index %d" % data.index(a)) break else: check("csv rows field-for-field re-derive", "all %d rows identical" % len(rows), "all %d rows identical" % len(rows)) # 3. Headline numbers. check("json commits == re-derived commit count", fixed.get("commits"), len(rows)) check("json earliest", fixed.get("earliest"), earliest) check("json first_commit", fixed.get("first_commit"), rows[-1]["hash"]) # 4. The top-10 by file-churn must reproduce the independent re-derivation. top = sorted(rows, key=lambda r: (-r["files"], r["date"], r["hash"]))[:10] exp_top = [(str(r["rank"]), r["short"], str(r["files"])) for r in top] obs_top = [] for rank, short, files in exp_top: for row in data: if row[0] == rank: obs_top.append((rank, short, files)) break check("top-10 (hash, files) == re-derivation", obs_top, exp_top) print("snapshot head: %s" % head) print("re-derived commits: %d | earliest: %s | latest: %s | first_commit: %s" % (len(rows), earliest, latest, rows[-1]["hash"])) if fails: print("CHECK FAIL: %s" % ", ".join(fails)) sys.exit(1) print("CHECK PASS: git commit-history extraction re-derives cleanly.") PY exit $?