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

149 lines
4.3 KiB
Python

#!/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())