137 lines
4.8 KiB
Python
137 lines
4.8 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/
|
|
|
|
# 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))
|