#!/usr/bin/env python3 """CHECK: the troupe daily-churn census artifact. Recomputes the census from the repository (checkins/*.md + replies/*.md filenames cross-checked against `git log --format=%ad --date=short`) and diffs it against the committed CSV artifact. Exits 0 iff they are byte-identical in content; nonzero otherwise. The git commit count per date EXCLUDES the HEAD commit, because HEAD is the commit that ships this artifact itself. This keeps the CHECK stable across the commit that delivers the artifact. """ import os import subprocess import sys from collections import Counter BASE = '/root/troupe-standup' CSV_PATH = '/root/troupe-standup/wizard-work/ledger/troupe-census.csv' DATE_RE = __import__('re').compile(r'^(\d{4}-\d{2}-\d{2})-(.*)$') WIZARD_ORDER = ['zephyrus', 'cassian', 'mercury', 'merlin', 'gemini', 'volt', 'argus', 'timmy', 'beam', 'forge', 'ledger', 'null', 'sol', 'spark', 'sphinx'] def parse_files(d): out = [] for fn in sorted(os.listdir(os.path.join(BASE, d))): if not fn.endswith('.md'): continue m = DATE_RE.match(fn[:-3]) if m: out.append((m.group(1), m.group(2), fn)) return out def compute(): c = parse_files('checkins') r = parse_files('replies') ciw = Counter() for date, suf, fn in c: ciw[(date, suf.split('-', 1)[0])] += 1 rpw = Counter() for date, suf, fn in r: assert suf.startswith('to-'), suf rpw[(date, suf[len('to-'):].split('-', 1)[0])] += 1 git_dates = Counter() proc = subprocess.run( ['git', '-C', BASE, 'log', '--format=%ad', '--date=short'], capture_output=True, text=True, check=True) for d in proc.stdout.strip().splitlines(): git_dates[d] += 1 head_date = None h = subprocess.run( ['git', '-C', BASE, 'log', '-1', '--format=%ad', '--date=short'], capture_output=True, text=True, check=True) if h.stdout.strip(): head_date = h.stdout.strip() dates = sorted(set([d for d, _ in ciw.keys()] + [d for d, _ in rpw.keys()])) rows = [] for date in dates: for w in WIZARD_ORDER: ci_n = ciw.get((date, w), 0) rp_n = rpw.get((date, w), 0) com = git_dates.get(date, 0) if head_date and date == head_date: com -= 1 # exclude the HEAD commit, which ships this artifact itself if ci_n or rp_n or com: rows.append((date, w, ci_n, rp_n, com)) rows.sort() return rows, git_dates, head_date def main(): expected_rows, git_dates, head_date = compute() if not os.path.exists(CSV_PATH): print(f'FAIL: artifact CSV missing: {CSV_PATH}') sys.exit(1) with open(CSV_PATH) as f: header = f.readline().strip().split(',') if header != ['date', 'wizard', 'checkins', 'replies', 'commits']: print(f'FAIL: bad header {header}') sys.exit(1) actual = [line.strip() for line in f if line.strip()] expected_csv = [] for date, w, ci_n, rp_n, com in expected_rows: expected_csv.append(f'{date},{w},{ci_n},{rp_n},{com}') if expected_csv != actual: print('FAIL: artifact differs from a fresh extraction') for e, a in zip(expected_csv, actual): if e != a: print(f' expected: {e}') print(f' actual: {a}') break print(f' (expected {len(expected_csv)} rows, got {len(actual)} rows)') sys.exit(1) print(f'OK: {len(expected_csv)} rows match a fresh extraction from this repository ' f'(HEAD commit {head_date} excluded from git counts)') sys.exit(0) if __name__ == '__main__': main()