110 lines
4.0 KiB
Python
110 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""extract_checkin_census_2026-10-27.py -- check-in census table.
|
|
|
|
Extract lane (data extraction + tables). Reads checkins/*.md in the troupe
|
|
repo, groups files by their leading YYYY-MM-DD date, and emits a per-wizard
|
|
tally table plus a full provenance record. The canonical table is one row per
|
|
wizard: `wizard<TAB>checkin_files`, sorted by count descending, name
|
|
ascending.
|
|
|
|
Artifact (written beside this script, under wizard-work/ledger/):
|
|
* 2026-10-27-checkin-census.tsv wizard<TAB>checkin_files table
|
|
* 2026-10-27-checkin-census.md human summary + per-date appendix
|
|
Reads use paths relative to this file's directory (repo-root agnostic).
|
|
"""
|
|
import collections
|
|
import os
|
|
import re
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
# Troupe repo root. Override with EXT_CENSUS_ROOT env var if set.
|
|
_ROOT = os.environ.get("EXT_CENSUS_ROOT") or (
|
|
"/root/troupe-standup"
|
|
if os.path.isdir("/root/troupe-standup/checkins")
|
|
else os.path.dirname(os.path.dirname(HERE))
|
|
)
|
|
SRC = os.path.join(_ROOT, "checkins")
|
|
OUT_TSV = os.path.join(HERE, "2026-10-27-checkin-census.tsv")
|
|
OUT_MD = os.path.join(HERE, "2026-10-27-checkin-census.md")
|
|
|
|
DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}-") # leading date on the filename
|
|
SUFFIX_RE = re.compile(r"-\d+$") # trailing -NNNN -> strip
|
|
|
|
|
|
def extract():
|
|
"""Return (per_date Counter, per_wizard Counter, excluded list)."""
|
|
per_date = collections.Counter()
|
|
per_wizard = collections.Counter()
|
|
excluded = []
|
|
with os.scandir(SRC) as it:
|
|
for entry in sorted(it, key=lambda e: e.name):
|
|
name = entry.name
|
|
if not name.endswith(".md"):
|
|
continue
|
|
if not DATE_RE.match(name):
|
|
excluded.append(name[:-3])
|
|
continue
|
|
date = name[:10]
|
|
rest = name[11:-3]
|
|
wizard = SUFFIX_RE.sub("", rest)
|
|
per_date[date] += 1
|
|
per_wizard[wizard] += 1
|
|
return per_date, per_wizard, excluded
|
|
|
|
|
|
def write_tables(per_date, per_wizard, excluded):
|
|
# Canonical table: one row per wizard, tab-separated.
|
|
rows = sorted(per_wizard.items(), key=lambda kv: (-kv[1], kv[0]))
|
|
with open(OUT_TSV, "w", encoding="utf-8") as f:
|
|
f.write("wizard\tcheckin_files\n")
|
|
for w, n in rows:
|
|
f.write(f"{w}\t{n}\n")
|
|
|
|
total_files = sum(per_date.values())
|
|
total_dates = len(per_date)
|
|
lines = [
|
|
"# Check-in census",
|
|
"",
|
|
"Extract lane table: per-wizard tally of `checkins/*.md` files (README.md",
|
|
"excluded). The latest day present is 2026-10-27 (three files filed).",
|
|
"",
|
|
"| wizard | checkin_files |",
|
|
"|---|---|",
|
|
]
|
|
lines += [f"| {w} | {n} |" for w, n in rows]
|
|
lines += [
|
|
"",
|
|
f"**Total files:** {total_files} across {total_dates} dates "
|
|
"(README.md excluded).",
|
|
"",
|
|
"## Per-date appendix",
|
|
"",
|
|
"| date | files |",
|
|
"|---|---|",
|
|
]
|
|
lines += [f"| {d} | {n} |" for d, n in sorted(per_date.items())]
|
|
lines += [
|
|
"",
|
|
"## Provenance",
|
|
"",
|
|
f"- Source: `checkins/*.md` in the troupe repo (as of 2026-10-27 06:00Z; "
|
|
f"{total_files} date-prefixed files, {total_dates} distinct dates).",
|
|
f"- Files excluded (no leading date): {len(excluded)} "
|
|
f"({', '.join(excluded) if excluded else 'none'}).",
|
|
"- `wizard` = filename with leading `YYYY-MM-DD-` and trailing `-{digits}` stripped.",
|
|
f"- Date-prefixed files: {total_files}; files excluded: {len(excluded)}.",
|
|
"- Check: `CHECK` recomputes this table from `checkins/` and diffs against the TSV.",
|
|
]
|
|
with open(OUT_MD, "w", encoding="utf-8") as f:
|
|
f.write("\n".join(lines) + "\n")
|
|
|
|
print(f"dates_with_files={total_dates} total_files={total_files} excluded={len(excluded)}")
|
|
print(f"wizards={len(rows)}")
|
|
print(f"wrote {OUT_TSV}")
|
|
print(f"wrote {OUT_MD}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
per_date, per_wizard, excluded = extract()
|
|
write_tables(per_date, per_wizard, excluded)
|