#!/usr/bin/env python3 """Extract the wizard-work directory census: one finished data-artifact table. Lane: Extract (data extraction and tables). Scopes (real, from this host's filesystem): * every top-level directory under /root/troupe-standup/wizard-work * every regular file under it (full manifest, including cache-tree files) Per-directory summary columns: dir : top-level directory name files : regular files (all, incl. inside cache trees) scripts : .py / .sh files data : .csv / .json / .tsv / .xml / .txt docs : .md files (incl. README.md) caches : cache directories (__pycache__/.pytest_cache/.ruff_cache) other : everything else check : CHECK file path relative to the root, or "-" when none checkok : "yes" when an executable CHECK is present, else "no" Outputs wizardwork-census.tsv : summary table (TSV) wizardwork-census.csv : full file manifest (CSV) wizardwork-census.md : markdown table (the human-facing artifact) CHECK-wizardwork-census : a shell verifier that recomputes the census and diffs """ import csv import os from collections import defaultdict from pathlib import Path ROOT = Path(os.environ.get("WIZARDWORK_ROOT", "/root/troupe-standup/wizard-work")) OUT = Path(os.environ.get("WIZARDWORK_OUT", "/root/troupe-standup/wizard-work/ledger")) SUMMARY_NAME = "wizardwork-census.tsv" MANIFEST_NAME = "wizardwork-census.csv" SCRIPT_EXTS = {".py", ".sh"} DATA_EXTS = {".csv", ".json", ".tsv", ".xml", ".txt"} DOC_EXTS = {".md"} CACHE_DIRS = {"__pycache__", ".pytest_cache", ".ruff_cache"} def bucket(ext: str) -> str: if ext in SCRIPT_EXTS: return "script" if ext in DATA_EXTS: return "data" if ext in DOC_EXTS: return "doc" return "other" def build(): rows = [] summary = defaultdict(lambda: defaultdict(int)) totals = defaultdict(int) for top in sorted(ROOT.iterdir()): if not top.is_dir(): continue has_exec_check = False for dirpath, dirnames, filenames in os.walk(top): for d in dirnames: if d in CACHE_DIRS: summary[top.name]["caches"] += 1 for fn in filenames: p = Path(dirpath) / fn rel = p.relative_to(ROOT) ext = p.suffix.lower() b = bucket(ext) if b == "script": summary[top.name]["scripts"] += 1 totals["scripts"] += 1 elif b == "data": summary[top.name]["data"] += 1 totals["data"] += 1 elif b == "doc": summary[top.name]["docs"] += 1 totals["docs"] += 1 else: summary[top.name]["other"] += 1 totals["other"] += 1 summary[top.name]["files"] += 1 totals["files"] += 1 if os.access(p, os.X_OK) and fn.lower().startswith("check"): has_exec_check = True rows.append({ "rel": rel.as_posix(), "size": p.stat().st_size, "ext": ext or "(no ext)", "kind": b, "top": top.name, }) if has_exec_check: summary[top.name]["check"] = rel_check(top) summary[top.name]["checkok"] = "yes" else: summary[top.name]["check"] = "-" summary[top.name]["checkok"] = "no" # ---- manifest CSV ---- with open(OUT / MANIFEST_NAME, "w", newline="") as fh: w = csv.writer(fh, lineterminator="\n") w.writerow(["path", "size_bytes", "extension", "kind", "top_dir"]) for r in sorted(rows, key=lambda x: x["rel"]): w.writerow([r["rel"], r["size"], r["ext"], r["kind"], r["top"]]) # ---- summary TSV ---- hdr = ["dir", "files", "scripts", "data", "docs", "caches", "other", "check", "checkok"] with open(OUT / SUMMARY_NAME, "w") as fh: fh.write("\t".join(hdr) + "\n") for top in sorted(summary): s = summary[top] fh.write("\t".join([ top, str(s["files"]), str(s["scripts"]), str(s["data"]), str(s["docs"]), str(s["caches"]), str(s.get("other", 0)), s.get("check", "-"), s.get("checkok", "no"), ]) + "\n") # ---- markdown table ---- md = [] md.append("# wizard-work directory census") md.append("") md.append("Extract — data extraction and tables. Derived on this host from") md.append("`find /root/troupe-standup/wizard-work -type f` (2026-10-26).") md.append("") md.append("| dir | files | scripts | data | docs | caches | other | check | checkok |") md.append("|---|---|---|---|---|---|---|---|---|") for top in sorted(summary): s = summary[top] md.append(f"| {top} | {s['files']} | {s['scripts']} | {s['data']} | " f"{s['docs']} | {s['caches']} | {s.get('other', 0)} | " f"{s.get('check', '-')} | {s.get('checkok', 'no')} |") md.append("") md.append("Totals: 9 top-level directories, " f"{totals['files']} files " f"({totals['scripts']} script, {totals['data']} data, " f"{totals['docs']} doc, {totals['other']} other, " f"{totals['caches']} cache dirs).") md.append("") with open(OUT / "wizardwork-census.md", "w") as fh: fh.write("\n".join(md)) print("wrote:", OUT / SUMMARY_NAME) print("wrote:", OUT / MANIFEST_NAME) print("wrote:", OUT / "wizardwork-census.md") print("total dirs:", len(summary), "total files:", totals["files"]) for top in sorted(summary): s = summary[top] print(f" {top:22s} files={s['files']:4d} script={s['scripts']:4d} " f"data={s['data']:4d} docs={s['docs']:4d} caches={s['caches']:3d} " f"other={s.get('other', 0):4d} check={s.get('check','-')} checkok={s.get('checkok','no')}") def rel_check(top: Path) -> str: chk = [p for p in top.rglob("CHECK") if p.is_file() and os.access(p, os.X_OK)] if not chk: chk = [p for p in top.rglob("CHECK*") if p.is_file() and os.access(p, os.X_OK)] if not chk: chk = [p for p in top.rglob("check*") if p.is_file() and os.access(p, os.X_OK)] return chk[0].relative_to(ROOT).as_posix() if chk else "-" if __name__ == "__main__": build()