116 lines
3.7 KiB
Python
116 lines
3.7 KiB
Python
#!/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-<recipient>-<N>.md
|
|
YYYY-MM-DD-to-<recipient>-interview.md (interview, no number by construction)
|
|
YYYY-MM-DD-to-<recipient>.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<date>\d{4}-\d{2}-\d{2})-to-(?P<recipient>[A-Za-z0-9_-]+)"
|
|
r"(?:-(?P<suffix>\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-<recipient>[-<N>|-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())
|