#!/usr/bin/env python3 """Extract the reply index from the troupe-standup replies/ directory. Lane: Extract -- data extraction and tables. Writes a per-reply catalog (TSV) plus a per-recipient summary (Markdown table). Accepted filenames: YYYY-MM-DD-to--.md YYYY-MM-DD-to--interview.md (interview, no number by construction) YYYY-MM-DD-to-.md (bare reply, no number) """ import glob import os import re import sys from collections import Counter from datetime import date REPO = "/root/troupe-standup" REPLIES_DIR = os.path.join(REPO, "replies") OUT_DIR = os.path.join(REPO, "wizard-work", "ledger") CATALOG_TSV = os.path.join(OUT_DIR, "replies-catalog-2026-11-02.tsv") SUMMARY_MD = os.path.join(OUT_DIR, "replies-catalog-2026-11-02.md") FILENAME_RE = re.compile( r"^(?P\d{4}-\d{2}-\d{2})-to-(?P[A-Za-z0-9_-]+)" r"(?:-(?P\d+|interview|preview))?\.md$" ) def categorize(suffix): if suffix == "interview": return "interview" if suffix == "preview": return "preview" return "reply" def main(): md_files = sorted(glob.glob(os.path.join(REPLIES_DIR, "*.md"))) assert md_files, "no .md files found" rows = [] other_files = [] for path in md_files: fn = os.path.basename(path) m = FILENAME_RE.match(fn) if m: suffix = m.group("suffix") or "" rows.append({ "date": m.group("date"), "recipient": m.group("recipient"), "number": suffix if suffix.isdigit() else "", "category": categorize(suffix), "file": fn, }) else: other_files.append(fn) os.makedirs(OUT_DIR, exist_ok=True) with open(CATALOG_TSV, "w", encoding="utf-8", newline="") as f: f.write("date\trecipient\tnumber\tcategory\tfile\n") for r in rows: f.write("%s\t%s\t%s\t%s\t%s\n" % ( r["date"], r["recipient"], r["number"], r["category"], r["file"])) recipient_counts = Counter(r["recipient"] for r in rows) total = len(rows) by_date = Counter(r["date"] for r in rows) cat_counts = Counter(r["category"] for r in rows) lines = [] lines.append("# Reply index — extracted %s" % date.today().isoformat()) lines.append("") lines.append("Source: `%s/replies/*.md` (files matching `YYYY-MM-DD-to-[-|-interview|-preview].md`)." % REPLIES_DIR) lines.append("") lines.append("## Per-recipient reply counts") lines.append("") lines.append("| recipient | replies |") lines.append("|---|---|") for recip in sorted(recipient_counts): lines.append("| %s | %d |" % (recip, recipient_counts[recip])) lines.append("| **total** | **%d** |" % total) lines.append("") lines.append("## Per-day reply counts") lines.append("") lines.append("| date | replies |") lines.append("|---|---|") for d in sorted(by_date): lines.append("| %s | %d |" % (d, by_date[d])) lines.append("| **total** | **%d** |" % total) lines.append("") lines.append("## Categories") lines.append("") lines.append("| category | count |") lines.append("|---|---|") for c in sorted(cat_counts): lines.append("| %s | %d |" % (c, cat_counts[c])) lines.append("| **total** | **%d** |" % total) lines.append("") with open(SUMMARY_MD, "w", encoding="utf-8") as f: f.write("\n".join(lines)) print("rows written:", total) print("categories:", dict(cat_counts)) print("recipients:", len(recipient_counts)) print("other_files:", other_files) print("catalog:", CATALOG_TSV) print("summary:", SUMMARY_MD) if __name__ == "__main__": sys.exit(main())