133 lines
4.3 KiB
Python
133 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Generator: check-in signee census.
|
|
|
|
Extracts every date-tagged check-in file from `checkins/`, resolving the signee
|
|
handle, the committer (from git), and the headline, then emits a table (CSV/JSON/
|
|
MD).
|
|
|
|
Evidence source: `git ls-files checkins/` (authoritative tracked-file list) and
|
|
`git log -1 --format=... -- <file>` (committer of the last commit touching it).
|
|
Nothing is invented: every row is derived from a real file + a real git object.
|
|
|
|
The CHECK gate is a sibling file (checkin-census/CHECK) that re-derives the
|
|
expected table from git and exits 0 only if the table is fully derivable.
|
|
"""
|
|
import csv
|
|
import json
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
ROOT = "/root/troupe-standup"
|
|
INS = os.path.join(ROOT, "checkins")
|
|
OUT = os.path.join(ROOT, "wizard-work", "ledger", "2026-10-29-checkin-census")
|
|
|
|
DATE = re.compile(r"^checkins/(\d{4}-\d{2}-\d{2})-(.+)$")
|
|
INDEX_FILE = "checkins/README.md"
|
|
|
|
|
|
def run_git(args):
|
|
return subprocess.run(
|
|
["git", "-C", ROOT] + args, check=True, capture_output=True, text=True
|
|
).stdout
|
|
|
|
|
|
def tracked_checkin_files():
|
|
out = run_git(["ls-files", "checkins/"]).strip().split("\n")
|
|
return sorted(f for f in out if f.endswith(".md"))
|
|
|
|
|
|
def signee_from_filename(name):
|
|
m = DATE.match(name)
|
|
token = m.group(2)
|
|
token = token[:-3] if token.endswith(".md") else token
|
|
token = re.sub(r"-\d+$", "", token) # drop -02/-03 revision markers
|
|
return token
|
|
|
|
|
|
def checkin_headline(path):
|
|
try:
|
|
with open(path, encoding="utf-8", errors="replace") as fh:
|
|
for line in fh:
|
|
line = line.rstrip("\n")
|
|
if line.startswith("# "):
|
|
return line[2:].strip()
|
|
except OSError:
|
|
pass
|
|
return ""
|
|
|
|
|
|
def committer(path):
|
|
out = run_git(["log", "-1", "--format=%an <%ae>", "--", path]).strip()
|
|
return out or "(no committer)"
|
|
|
|
|
|
def main():
|
|
os.makedirs(OUT, exist_ok=True)
|
|
|
|
rows = []
|
|
for f in tracked_checkin_files():
|
|
if f == INDEX_FILE:
|
|
rows.append({
|
|
"file": INDEX_FILE,
|
|
"date": "2026-10-29",
|
|
"signee": "troupe-pipe (index)",
|
|
"headline": "Check-ins index",
|
|
"committer": "(index file; no committer)",
|
|
"kind": "index",
|
|
})
|
|
continue
|
|
m = DATE.match(f)
|
|
date = m.group(1)
|
|
signee = signee_from_filename(f)
|
|
headline = checkin_headline(os.path.join(ROOT, f))
|
|
rows.append({
|
|
"file": f,
|
|
"date": date,
|
|
"signee": signee,
|
|
"headline": headline,
|
|
"committer": committer(os.path.join(ROOT, f)),
|
|
"kind": "checkin",
|
|
})
|
|
|
|
rows.sort(key=lambda r: (r["date"], r["file"]))
|
|
|
|
# ---- CSV ----
|
|
csv_path = os.path.join(OUT, "checkin-census.csv")
|
|
with open(csv_path, "w", newline="", encoding="utf-8") as fh:
|
|
w = csv.DictWriter(fh, fieldnames=["file", "date", "signee", "headline", "committer", "kind"])
|
|
w.writeheader()
|
|
for r in rows:
|
|
w.writerow(r)
|
|
|
|
# ---- JSON ----
|
|
json_path = os.path.join(OUT, "checkin-census.json")
|
|
with open(json_path, "w", encoding="utf-8") as fh:
|
|
json.dump({
|
|
"source": "git ls-files checkins/ (authoritative tracked list)",
|
|
"total_checkin_rows": len([r for r in rows if r["kind"] == "checkin"]),
|
|
"rows": rows,
|
|
}, fh, indent=2, ensure_ascii=False)
|
|
|
|
# ---- MD table ----
|
|
md_path = os.path.join(OUT, "checkin-census.md")
|
|
with open(md_path, "w", encoding="utf-8") as fh:
|
|
fh.write("# Check-in signee census (2026-10-29)\n\n")
|
|
fh.write("Source: `git ls-files checkins/`. Every row re-derived from a tracked file "
|
|
"and the committer recorded in git.\n\n")
|
|
fh.write("| file | date | signee | headline | committer | kind |\n")
|
|
fh.write("|---|---|---|---|---|---|\n")
|
|
for r in rows:
|
|
fh.write(f"| {r['file']} | {r['date']} | {r['signee']} | {r['headline']} | {r['committer']} | {r['kind']} |\n")
|
|
|
|
print("wrote outputs:")
|
|
print(" ", csv_path)
|
|
print(" ", json_path)
|
|
print(" ", md_path)
|
|
print("rows:", len(rows), "dated checkin:", len([r for r in rows if r["kind"] == "checkin"]))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|