147 lines
4.4 KiB
Python
147 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""verify_head_commits.py — ledger 20-commit table gate (Extract lane).
|
|
|
|
Re-derives the last-20-commits table from the live HEAD revision
|
|
(039246958fcf802aba9224aa5c24fad6bf181dc5) and diffs freshly derived bytes
|
|
against the committed table files in this directory (commits.tsv / json / detail.tsv /
|
|
md). Exits 0 = correct (all four committed files byte-identical to git-derived
|
|
bytes, and every row's Files equals the recomputed changed-path count);
|
|
nonzero = any mismatch or a stale snapshot.
|
|
|
|
Run: python3 verify_head_commits.py
|
|
or from the CHECK wrapper: bash CHECK
|
|
"""
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
|
|
REPO = "/root/troupe-standup"
|
|
OUT_DIR = "/root/troupe-standup/wizard-work/ledger/2026-10-25-head-20-commits"
|
|
PINNED_REV = "039246958fcf802aba9224aa5c24fad6bf181dc5"
|
|
N = 20
|
|
FILES = ["commits.tsv", "commits.json", "commits_detail.tsv", "commits.md"]
|
|
|
|
|
|
def git(*args):
|
|
return subprocess.run(
|
|
["git", "-C", REPO] + list(args), check=True, capture_output=True, text=True
|
|
).stdout
|
|
|
|
|
|
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 (pinned to HEAD)",
|
|
"",
|
|
"Source: `git -C /root/troupe-standup log -n 20 --format='%x1f%H%x1f%h%x1f%an%x1f%aI%x1f%s'` @ {0}".format(PINNED_REV),
|
|
"",
|
|
"Extract-lane table: `Files` = number of distinct paths changed in the commit "
|
|
"(git show --name-status), re-derived and verified against git in CHECK.",
|
|
"",
|
|
"| 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}/{1}".format(OUT_DIR, 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 in FILES:
|
|
exp = derived[name]
|
|
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 {0} commits from live HEAD {1} (git log -n 20 {1}); "
|
|
"commits.tsv/json/detail.tsv/md byte-identical to git-derived bytes; "
|
|
"Files column = true changed-path count".format(len(rows), PINNED_REV)
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|