76 lines
2.8 KiB
Bash
Executable File
76 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# CHECK — git author census re-derivation verification.
|
|
#
|
|
# Re-derives the identity census from live `git log` (current branch HEAD) and
|
|
# compares it, field-for-field, against the committed
|
|
# git-author-census-2026-10-23.json. Exits 0 only on exact match.
|
|
set -u
|
|
|
|
REPO=/root/troupe-standup
|
|
OUT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
JSON="$OUT/git-author-census-2026-10-23.json"
|
|
MD="$OUT/git-author-census-2026-10-23.md"
|
|
|
|
echo "[CHECK] re-deriving identity census from git log (HEAD) ..."
|
|
python3 - "$JSON" "$MD" <<'PY'
|
|
import json, subprocess, sys
|
|
from collections import Counter, defaultdict
|
|
|
|
json_path, md_path = sys.argv[1], sys.argv[2]
|
|
repo = "/root/troupe-standup"
|
|
|
|
def derive():
|
|
out = subprocess.run(
|
|
["git", "-C", repo, "log", "--format=%an%x00%ae%x00%ad", "--date=iso-strict"],
|
|
capture_output=True, text=True, check=True).stdout
|
|
by_pair = defaultdict(list)
|
|
for line in out.splitlines():
|
|
if not line.strip():
|
|
continue
|
|
name, email, date = line.split("\x00")
|
|
by_pair[(name, email)].append(date)
|
|
rows = []
|
|
for (name, email), dates in by_pair.items():
|
|
rows.append({"name": name, "email": email, "count": len(dates),
|
|
"first": min(dates), "last": max(dates)})
|
|
name_counts = Counter(r["name"] for r in rows)
|
|
email_counts = Counter(r["email"] for r in rows)
|
|
for r in rows:
|
|
r["name_collides"] = name_counts[r["name"]] > 1
|
|
r["email_collides"] = email_counts[r["email"]] > 1
|
|
rows.sort(key=lambda r: (-r["count"], r["name"], r["email"]))
|
|
return rows
|
|
|
|
expected = derive()
|
|
committed = json.load(open(json_path))["census"]
|
|
|
|
if len(expected) != len(committed):
|
|
print(" LENGTH MISMATCH: derived %d rows, committed %d rows" %
|
|
(len(expected), len(committed)), file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
for i, (e, c) in enumerate(zip(expected, committed)):
|
|
for k in ("name", "email", "count", "first", "last", "name_collides", "email_collides"):
|
|
if e.get(k) != c.get(k):
|
|
print(" ROW %d FIELD %r MISMATCH: derived=%r committed=%r" %
|
|
(i, k, e.get(k), c.get(k)), file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
print("[CHECK] derived %d identity rows; exact match against %s — PASS" %
|
|
(len(expected), json_path))
|
|
|
|
d = json.load(open(json_path))
|
|
md = open(md_path).read()
|
|
for needle in [str(d["total_commits"]), str(d["distinct_identities"]),
|
|
str(len(set(c["name"] for c in d["census"]))),
|
|
str(len(set(c["email"] for c in d["census"])))]:
|
|
if needle not in md:
|
|
print(" HEADLINE MISMATCH: missing " + needle, file=sys.stderr)
|
|
sys.exit(1)
|
|
print("[CHECK] headline totals present in .md — PASS")
|
|
PY
|
|
if [ $? -ne 0 ]; then exit 1; fi
|
|
|
|
echo "CHECK PASS: git author census re-derives cleanly."
|
|
exit 0
|