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