Files
troupe-standup/wizard-work/ledger/check_2026-11-01-commit-census
T

140 lines
5.2 KiB
Python
Executable File

#!/usr/bin/env python3
"""Verifier for repo-2026-11-01-commit-census.tsv.
The daily commit-author census is a SNAPSHOT of the repo at revision
BASELINE (d27c03f0e4651c9a4ee9323830d6d795f0d2b40a), taken before the ledger
census commit landed. HEAD moves as later commits (including this pipe's own
ledger commits) are added, so the check must regenerate from BASELINE, not from
the moving HEAD.
Re-derives the 2026-11-01 commit-author census from git at BASELINE and compares
it against the artifact. Exit code 0 = artifact matches git (verdict correct),
nonzero = mismatch.
Usage: python3 check_2026-11-01-commit-census.py
"""
import subprocess
import sys
REPO = "/root/troupe-standup"
TSV = "/root/.hermes/wizard-outputs/ledger/repo-2026-11-01-commit-census.tsv"
DATE = "2026-11-01"
# Revision the snapshot was taken from. bdfb48a (the ledger census commit) sits
# on top of this; it must not be part of the data it describes.
BASELINE = "d27c03f0e4651c9a4ee9323830d6d795f0d2b40a"
WIZARD_BY_EMAIL = {
"timmy@stackchain.ai": "Timmy",
"timmy@alexanderwhitestone.com": "Timmy",
"timmy@agents.invalid": "Timmy",
"timmy@stackchain.invalid": "Timmy",
"timmy@hermes": "Timmy",
"timmy@stacktimmy.invalid": "Timmy",
"timmy@localhost": "Timmy",
"timmy@alexandrewswhitestone.com": "Timmy",
"timmy@stachain.ai": "Timmy",
"zephyrus-sparkborn@agents.invalid": "Zephyrus Sparkborn",
"zephyrus-sparkborn@users.noreply.forge.alexanderwhitestone.com": "Zephyrus Sparkborn",
"zephyrus-sparkborn@users.noreply.github.com": "Zephyrus Sparkborn",
"zephyrus-sparkborn@noreply.local": "Zephyrus Sparkborn",
"zephyrus@alexanderwhitestone.com": "Zephyrus Sparkborn",
"cassian@agents.invalid": "Cassian Assayborn",
"cassian@forge.local": "Cassian Assayborn",
"volt@agents.invalid": "Volt",
"volt@troupe.invalid": "Volt",
"volt@troupe.local": "Volt",
"volt@stackchain.local": "Volt",
"volt@alexanderwhitestone.com": "Volt",
"volt@stackchain.ai": "Volt",
"ledger@agents.invalid": "Ledger",
"forge@agents.invalid": "Forge",
"mercury@agents.invalid": "Mercury",
"merlin@agents.invalid": "Merlin",
"sol@agents.invalid": "Sol",
"quill@agents.invalid": "Quill",
"sphinx@agents.invalid": "Sphinx",
"null@agents.invalid": "Null",
"argus@agents.invalid": "Argus",
"argus@troupe": "Argus",
"sentinel@troupe-standup.internal": "Sentinel",
"beam@agents.invalid": "Beam",
"troupe-pipe@agents.invalid": "Troupe-pipe",
"pipe@localhost": "Pipe",
}
def git(*args):
return subprocess.run(
["git", "-C", REPO] + list(args), check=True, capture_output=True, text=True
).stdout
def recompute():
rows = []
for line in git("log", BASELINE, "--format=%an\t%ae\t%aI\t%H\t%s").splitlines():
p = line.split("\t")
if len(p) == 5 and p[2].startswith(DATE + "T"):
rows.append(p)
groups = {}
for name, email, adate, sha, subject in rows:
wizard = WIZARD_BY_EMAIL.get(email, "Unmapped")
groups.setdefault(wizard, []).append((adate, sha))
out = []
for wizard, recs in groups.items():
recs.sort()
out.append({
"wizard": wizard,
"commits": len(recs),
"first_commit": recs[0][0],
"last_commit": recs[-1][0],
"latest_sha": recs[-1][1],
})
return out
def main():
expected = recompute()
expected.sort(key=lambda r: (-r["commits"], r["wizard"]))
with open(TSV, encoding="utf-8") as f:
lines = [ln for ln in f.read().splitlines() if ln.strip()]
header, data = lines[0], lines[1:]
problems = []
if header != "wizard\tcommits\tfirst_commit\tlast_commit\tlatest_sha\tsubjects":
problems.append(f"header={header!r}")
if len(data) != len(expected):
problems.append(f"row count: artifact={len(data)} git@baseline={len(expected)}")
total_expected = sum(r["commits"] for r in expected)
total_artifact = sum(int(r.split("\t")[1]) for r in data if len(r.split("\t")) == 6)
if total_expected != total_artifact:
problems.append(f"total commits: artifact={total_artifact} git@baseline={total_expected}")
for i, (art, exp) in enumerate(zip(data, expected)):
fields = art.split("\t")
if len(fields) != 6:
problems.append(f"row {i}: {len(fields)} fields")
continue
wizard, commits, first, last, sha, subjects = fields
checks = [
(wizard == exp["wizard"], f"row {i} wizard {wizard} != {exp['wizard']}"),
(int(commits) == exp["commits"], f"row {i} commits {commits} != {exp['commits']}"),
(first == exp["first_commit"], f"row {i} first {first} != {exp['first_commit']}"),
(last == exp["last_commit"], f"row {i} last {last} != {exp['last_commit']}"),
(sha == exp["latest_sha"], f"row {i} sha {sha} != {exp['latest_sha']}"),
]
problems += [msg for ok, msg in checks if not ok]
if problems:
print("REPO CENSUS MISMATCH")
for p in problems:
print(" -", p)
sys.exit(1)
print(f"REPO CENSUS OK: snapshot at {BASELINE}; {len(expected)} wizard rows, "
f"{total_expected} commits on {DATE} match git")
sys.exit(0)
if __name__ == "__main__":
main()