Files
troupe-standup/wizard-work/ledger/extract_checkin_census.py
T

134 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""Extract the per-wizard check-in cadence census from checkins/*.md.
Lane: Extract (data extraction and tables).
Scopes (real, from this host's filesystem):
* every *.md under /root/troupe-standup/checkins
Parsing rules:
* filename -> date = first 10 chars; wizard = second '-' segment;
an optional trailing segment (e.g. "-02", "-03", "-wizards")
is dropped (the "canonical" entry name wins).
* body -> the first "# " H1 line of the file (truncated to 70 chars).
Outputs
checkin-census.tsv : summary table (TSV)
checkin-cadence.tsv : one row per date x wizard (TSV)
checkin-census.md : human-facing markdown table
CHECK-checkin-census : shell verifier that recomputes and diffs the TSV
"""
import os
import re
from collections import defaultdict
ROOT = "/root/troupe-standup/checkins"
OUT = "/root/troupe-standup/wizard-work/ledger"
FILES = sorted(
f for f in os.listdir(ROOT)
if f.endswith(".md") and re.match(r"^\d{4}-\d{2}-\d{2}", f)
)
# canonical wizard name -> display name
WIZARD_DISPLAY = {
"zephyrus": "Zephyrus Sparkborn",
"mercury": "Mercury",
"merlin": "Merlin",
"cassian": "Cassian Assayborn",
"volt": "Volt",
"gemini": "Gemini",
"argus": "Argus",
"beam": "Beam",
}
DISPLAY_WIZARD = {
"Zephyrus Sparkborn": "zephyrus",
"Mercury": "mercury",
"Merlin": "merlin",
"Cassian Assayborn": "cassian",
"Volt": "volt",
"Gemini": "gemini",
"Argus": "argus",
"Beam": "beam",
}
def parse_name(f):
base = f[:-3] # strip .md
date = base[:10]
rest = base[11:]
parts = rest.split("-")
wizard = parts[0]
return date, wizard
def first_h1(f):
with open(os.path.join(ROOT, f), encoding="utf-8") as fh:
for line in fh:
if line.startswith("# "):
return line[2:].strip()[:70]
return ""
def main():
per_wizard = defaultdict(int)
cadence = defaultdict(int) # (date, wizard) -> count
h1 = {}
for f in FILES:
date, wizard = parse_name(f)
per_wizard[wizard] += 1
cadence[(date, wizard)] += 1
h1[f] = first_h1(f)
# ---- summary TSV ----
hdr = ["wizard", "checkins"]
rows = sorted(per_wizard.items())
with open(os.path.join(OUT, "checkin-census.tsv"), "w") as fh:
fh.write("\t".join(hdr) + "\n")
for w, c in rows:
fh.write(f"{w}\t{c}\n")
# ---- cadence TSV ----
hdr = ["date", "wizard", "count"]
with open(os.path.join(OUT, "checkin-cadence.tsv"), "w") as fh:
fh.write("\t".join(hdr) + "\n")
for (date, wizard), c in sorted(cadence.items()):
fh.write(f"{date}\t{wizard}\t{c}\n")
# ---- markdown table ----
md = []
md.append("# Check-in census")
md.append("")
md.append("Extract — data extraction and tables. Derived from"
" `ls checkins/*.md` (2026-10-27).")
md.append("")
md.append(f"Total check-in files: **{len(FILES)}**")
md.append("")
md.append("| Wizard | Check-ins |")
md.append("|---|---|")
for w, c in rows:
md.append(f"| {WIZARD_DISPLAY.get(w, w)} | {c} |")
md.append("")
md.append("## Per-date cadence (check-ins per wizard)")
md.append("")
md.append("| Date | wizard | check-ins |")
md.append("|---|---|---|")
for (date, wizard), c in sorted(cadence.items()):
md.append(f"| {date} | {WIZARD_DISPLAY.get(wizard, wizard)} | {c} |")
md.append("")
with open(os.path.join(OUT, "checkin-census.md"), "w") as fh:
fh.write("\n".join(md))
print("wrote checkin-census.tsv")
print("wrote checkin-cadence.tsv")
print("wrote checkin-census.md")
print("total files:", len(FILES))
for w, c in rows:
print(f" {w:24s} {c}")
if __name__ == "__main__":
main()