Files
troupe-standup/wizard-work/ledger/2026-10-31-wizardwork-census.py
T

142 lines
4.9 KiB
Python

#!/usr/bin/env python3
"""Extract the committed worktree census of the entire `wizard-work/` area at HEAD.
Lane: ledger (Extract — data extraction and tables).
Deliverable (all inside wizard-work/ledger/):
2026-10-31-wizardwork-census.{md,csv,json} — the finished artifact
2026-10-31-wizardwork-census.py — the extraction script (reproduces it)
CHECK — independent verifier (exit 0 = correct)
Source of truth: `git ls-tree -r HEAD`. "Files" = blob objects in the committed
tree; untracked files are excluded. Scope: every directory directly under
wizard-work/ (one row per lane). A flat manifest of every committed path is
also emitted.
Run: python3 2026-10-31-wizardwork-census.py
"""
import json
import os
import subprocess
REPO = "/root/troupe-standup"
OUT = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
os.makedirs(OUT, exist_ok=True)
DAY = "2026-10-31"
SCOPE = "wizard-work/" # only directories directly under wizard-work/
LANE_ORDER = sorted(
l
for l in os.listdir(REPO)
if os.path.isdir(os.path.join(REPO, l)) and os.path.isdir(os.path.join(REPO, l, ".git"))
)
# Committed-tree inventory at HEAD (mode SP type SP object SP size SP path).
_out = subprocess.check_output(
["git", "ls-tree", "-r", "-l", "HEAD"], cwd=REPO, text=True,
).strip().splitlines()
head_sha = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=REPO, text=True).strip()
total_files = 0
total_bytes = 0
lanes = {}
exts = {}
for line in _out:
_mode, otype, _obj, size_s, path = line.split()
if otype != "blob" or not path.startswith(SCOPE):
continue
# lane = the directory immediately after wizard-work/
tail = path[len(SCOPE):]
lane = tail.split("/", 1)[0]
if lane not in lanes:
lanes[lane] = [0, 0]
lanes[lane][0] += 1
lanes[lane][1] += int(size_s)
ext = tail.rsplit(".", 1)[-1] if "." in tail else "(no-ext)"
exts[ext] = exts.get(ext, [0, 0])
exts[ext][0] += 1
exts[ext][1] += int(size_s)
total_files += 1
total_bytes += int(size_s)
manifest = []
for _line in _out:
_mode, _otype, _obj, _size_s, _path = _line.split()
if _otype == "blob" and _path.startswith(SCOPE):
manifest.append({"rel_path": _path[len(SCOPE):], "size_bytes": int(_size_s)})
summary = {
"source": "git ls-tree -r HEAD (committed worktree tree), scoped to %s" % SCOPE,
"head_sha": head_sha,
"day": DAY,
"total_files": total_files,
"total_bytes": total_bytes,
"lanes_covered": sorted(lanes),
}
def md_table(rows):
out = ["| lane | files | bytes |", "|---|---|---|"]
for name, (count, b) in sorted(rows.items(), key=lambda kv: (-kv[1][0], kv[0])):
out.append("| %s | %d | %d |" % (name, count, b))
out.append("| **total** | **%d** | **%d** |" % (total_files, total_bytes))
return "\n".join(out)
md = [
"# %s — committed file-tree census of `wizard-work/` (HEAD %s)'"
% (DAY, head_sha),
"",
"Source of truth: `git ls-tree -r HEAD`. \"Files\" = blob objects in the committed tree;",
"untracked files are excluded. Scope: every directory directly under `wizard-work/`.",
"Every figure is re-derived by the CHECK script from git itself, so the artifact cannot drift.",
"",
"## Summary",
"",
"| figure | value |",
"|---|---|",
"| committed files (blobs) | %d |" % total_files,
"| committed bytes | %d |" % total_bytes,
"| revision | %s |" % head_sha,
"| lanes covered | %d |" % len(lanes),
"",
"## By lane (files / bytes)",
"",
md_table(lanes),
"",
"## By extension (files / bytes)",
"",
md_table(exts),
"",
"## Flat manifest",
"",
"| rel_path | size_bytes | head_sha |",
"|---|---|---|",
]
md += ["| %s | %d | %s |" % (m["rel_path"], m["size_bytes"], head_sha)
for m in sorted(manifest, key=lambda r: r["rel_path"])]
md += [""]
data = {
"summary": summary,
"by_lane": {k: {"files": v[0], "bytes": v[1]} for k, v in lanes.items()},
"by_extension": {k: {"files": v[0], "bytes": v[1]} for k, v in exts.items()},
"manifest": manifest,
}
with open(os.path.join(OUT, "%s-wizardwork-census.json" % DAY), "w") as f:
json.dump(data, f, indent=2, sort_keys=True)
with open(os.path.join(OUT, "%s-wizardwork-census.csv" % DAY), "w") as f:
f.write("rel_path,size_bytes,head_sha\n")
for m in sorted(manifest, key=lambda r: r["rel_path"]):
f.write("%s,%d,%s\n" % (m["rel_path"], m["size_bytes"], head_sha))
with open(os.path.join(OUT, "%s-wizardwork-census.md" % DAY), "w") as f:
f.write("\n".join(md) + "\n")
print("HEAD=%s" % head_sha)
print("files=%d bytes=%d" % (total_files, total_bytes))
print("lanes=%s" % ", ".join("%s:%d" % (k, v[0]) for k, v in sorted(lanes.items(), key=lambda kv: -kv[1][0])))
print("exts=%s" % ", ".join("%s:%d" % (k, v[0]) for k, v in sorted(exts.items(), key=lambda kv: -kv[1][0])))
print("wrote %s" % os.path.join(OUT, "%s-wizardwork-census.json" % DAY))