#!/usr/bin/env python3 """verify_commits_check.py — the ledger 20-commit table gate (Extract lane). Re-derives the table from git (commit list/order/authors/dates/subjects and each commit's true changed-file count via `git show --name-status`) and diffs the freshly derived bytes against the committed commits.{md,tsv,json,detail.tsv}. Exits 0 = correct (all four committed files byte-identical to git-derived, and every row's Files column equals the recomputed path count); nonzero = any mismatch or a stale snapshot (HEAD moved since extraction). Run it directly, or from the repo's CHECK: bash CHECK """ import json import subprocess import sys REPO = "/root/troupe-standup" N = 20 def git(*args): return subprocess.run( ["git", "-C", REPO] + list(args), check=True, capture_output=True, text=True ).stdout PINNED_REV = "d4ffaa3" # short rev the snapshot was read from (NOT HEAD, which has moved on) def derive_rows(): fmt = "%H%x1f%h%x1f%an%x1f%aI%x1f%s" commits = [ln for ln in git("log", "-n", str(N), "--format=" + fmt, PINNED_REV).splitlines() if ln.strip()] rows = [] for ln in commits: full, short, author, date, subject = ln.split("\x1f") ns = git("show", "--name-status", "--format=", full) files = [l2.split("\t", 1)[1] for l2 in ns.splitlines() if l2.strip()] rows.append( { "rank": len(rows) + 1, "full": full, "short": short, "author": author, "date": date, "subject": subject, "files": files, } ) return rows def tsv(rows): b = ["Rank\tHash\tFull\tAuthor\tDate\tSubject\tFiles"] for r in rows: b.append( "\t".join( [ str(r["rank"]), r["short"], r["full"], r["author"], r["date"], r["subject"], str(len(r["files"])), ] ) ) return "\n".join(b) + "\n" def json_rows(rows): return json.dumps(rows, indent=2) + "\n" def detail(rows): b = ["Rank\tHash\tFile"] for r in rows: for f in r["files"]: b.append("\t".join([str(r["rank"]), r["short"], f])) return "\n".join(b) + "\n" def md(rows): b = [ "# Troupe repository commit history — last 20 commits", "", "Source: `git -C /root/troupe-standup log -n 20 --format='%x1f%H%x1f%h%x1f%an%x1f%aI%x1f%s'`", "", "Extract-lane correction: `Files` = number of distinct paths changed in the commit " "(git show --name-status), re-derived and verified against git in `CHECK`.", "", "Pinned revision: d4ffaa3", "| Rank | Hash | Author | Date | Subject | Files |", "| --- | --- | --- | --- | --- | --- |", ] for r in rows: b.append( "| {0} | {1} | {2} | {3} | {4} | {5} |".format( r["rank"], r["short"], r["author"], r["date"], r["subject"], len(r["files"]) ) ) return "\n".join(b) + "\n" def read(name): with open("{0}/wizard-work/ledger/{1}".format(REPO, name)) as fh: return fh.read() def main(): rows = derive_rows() derived = { "commits.tsv": tsv(rows), "commits.json": json_rows(rows), "commits_detail.tsv": detail(rows), "commits.md": md(rows), } failures = [] for name, exp in derived.items(): got = read(name) if got != exp: failures.append( "{0}: committed {1} bytes, git-derived {2} bytes".format( name, len(got), len(exp) ) ) # Independently re-check the Files column is the true changed-path count. for r in rows: if not r["files"]: failures.append("rank {0} {1}: Files=0".format(r["rank"], r["short"])) if failures: print("CHECK FAIL") for f in failures: print(" -", f) return 1 print( "CHECK PASS | re-derived %d commits from pinned revision %s (git log -n 20 %s); commits.tsv/json/detail.tsv/md " "byte-identical to git-derived bytes; Files column = true changed-path count" % (len(rows), PINNED_REV, PINNED_REV) ) return 0 if __name__ == "__main__": sys.exit(main())