ledger: extension census 2026-11-03 verified 31 rows
This commit is contained in:
1 parent
7ed56b2170
commit
320474b1f9
7 files changed
+296
No files matched your search
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# CHECK -- extension census (extract lane). Exit 0 iff the committed
|
||||
# wizard-work/ledger/extension-census.csv is byte-identical to a fresh
|
||||
# re-derivation from repo_files.tsv.
|
||||
set -u
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 2
|
||||
exec python3 wizard-work/ledger/verify_extension_census.py
|
||||
@@ -0,0 +1,27 @@
|
||||
# Extension census 2026-11-03
|
||||
|
||||
Ranked census of file extensions across the troupe worktree.
|
||||
|
||||
- **Source:** `repo_files.tsv` (rank<TAB>path inventory, 3345 file rows).
|
||||
- **Artifact:** `extension-census.csv` (rank, extension, file_count) — 31 rows.
|
||||
- **Interactive view:** `extension-census.md` (ranked table + totals).
|
||||
- **Independent verifier:** `verify_extension_census.py` — re-derives from
|
||||
`repo_files.tsv` with a standalone loop and asserts byte-match; exit 0.
|
||||
- **CHECK file:** `../CHECK-extension-census-2026-11-03`.
|
||||
|
||||
Ranked top of the census (full list in `extension-census.csv`):
|
||||
|
||||
| rank | extension | file_count |
|
||||
|---|---|---|
|
||||
| 1 | .md | 829 |
|
||||
| 2 | .png | 803 |
|
||||
| 3 | .py | 653 |
|
||||
| 4 | .txt | 551 |
|
||||
| 5 | .json | 231 |
|
||||
| 6 | .sh | 56 |
|
||||
| 7 | .html | 55 |
|
||||
| 8 | .csv | 43 |
|
||||
| 9 | .svg | 31 |
|
||||
| 10 | .age | 16 |
|
||||
|
||||
**Totals:** 3345 files, 31 unique extensions.
|
||||
@@ -0,0 +1,32 @@
|
||||
rank,extension,file_count
|
||||
1,.md,829
|
||||
2,.png,803
|
||||
3,.py,653
|
||||
4,.txt,551
|
||||
5,.json,231
|
||||
6,.sh,56
|
||||
7,.html,55
|
||||
8,.csv,43
|
||||
9,.svg,31
|
||||
10,.age,16
|
||||
11,.tsv,15
|
||||
12,.xml,12
|
||||
13,(none),11
|
||||
14,.gitignore,5
|
||||
15,.log,5
|
||||
16,.pdf,4
|
||||
17,.sha256,4
|
||||
18,.jsonl,3
|
||||
19,.mp3,3
|
||||
20,.c,2
|
||||
21,.diff,2
|
||||
22,.jpg,2
|
||||
23,.check,1
|
||||
24,.dl,1
|
||||
25,.goyiwz,1
|
||||
26,.gz,1
|
||||
27,.mailmap,1
|
||||
28,.md5,1
|
||||
29,".py""""",1
|
||||
30,.rc,1
|
||||
31,.yaml,1
|
||||
|
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"source": "repo_files.tsv",
|
||||
"rows": 31,
|
||||
"total_files": 3345,
|
||||
"unique_extensions": 31,
|
||||
"extractor": "extract_extension_census.py",
|
||||
"verifier": "verify_extension_census.py",
|
||||
"check": "CHECK-extension-census-2026-11-03",
|
||||
"created_utc": "2026-11-03T00:00:00Z"
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
# Extension census
|
||||
|
||||
Ranked census of file extensions across the troupe worktree (re-derived from `repo_files.tsv` by `extract_extension_census.py`).
|
||||
|
||||
| rank | extension | file_count |
|
||||
|---|---|---|
|
||||
| 1 | .md | 829 |
|
||||
| 2 | .png | 803 |
|
||||
| 3 | .py | 653 |
|
||||
| 4 | .txt | 551 |
|
||||
| 5 | .json | 231 |
|
||||
| 6 | .sh | 56 |
|
||||
| 7 | .html | 55 |
|
||||
| 8 | .csv | 43 |
|
||||
| 9 | .svg | 31 |
|
||||
| 10 | .age | 16 |
|
||||
| 11 | .tsv | 15 |
|
||||
| 12 | .xml | 12 |
|
||||
| 13 | (none) | 11 |
|
||||
| 14 | .gitignore | 5 |
|
||||
| 15 | .log | 5 |
|
||||
| 16 | .pdf | 4 |
|
||||
| 17 | .sha256 | 4 |
|
||||
| 18 | .jsonl | 3 |
|
||||
| 19 | .mp3 | 3 |
|
||||
| 20 | .c | 2 |
|
||||
| 21 | .diff | 2 |
|
||||
| 22 | .jpg | 2 |
|
||||
| 23 | .check | 1 |
|
||||
| 24 | .dl | 1 |
|
||||
| 25 | .goyiwz | 1 |
|
||||
| 26 | .gz | 1 |
|
||||
| 27 | .mailmap | 1 |
|
||||
| 28 | .md5 | 1 |
|
||||
| 29 | .py"" | 1 |
|
||||
| 30 | .rc | 1 |
|
||||
| 31 | .yaml | 1 |
|
||||
|
||||
**Total files: 3345**
|
||||
**Unique extensions: 31**
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Extract a ranked file-extension census from wizard-work/ledger/repo_files.tsv.
|
||||
|
||||
Source: repo_files.tsv is a (rank, path) inventory of the troupe worktree:
|
||||
rank<TAB>path
|
||||
|
||||
Some path cells were written through a Python repr/json serializer and carry
|
||||
escaped quotes/newlines; we de-escape, take the basename, and count
|
||||
extensions (lowercased, leading dot on the suffix unless there is none,
|
||||
which is emitted as the literal "(none)").
|
||||
|
||||
Output (extension-census.csv):
|
||||
rank,extension,file_count
|
||||
1,.md,829
|
||||
...
|
||||
|
||||
and extension-census.md (ranked + totals row). Run:
|
||||
python3 extract_extension_census.py
|
||||
"""
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
from collections import Counter
|
||||
|
||||
REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
SRC = os.path.join(REPO, "repo_files.tsv")
|
||||
OUT_CSV = os.path.join(REPO, "wizard-work", "ledger", "extension-census.csv")
|
||||
OUT_MD = os.path.join(REPO, "wizard-work", "ledger", "extension-census.md")
|
||||
|
||||
|
||||
def clean_path(raw: str) -> str:
|
||||
s = raw.strip()
|
||||
# De-quote a cell that was wrapped in double quotes (Python repr / json).
|
||||
if len(s) >= 2 and s[0] == '"' and s[-1] == '"':
|
||||
s = s[1:-1]
|
||||
# De-escape backslash escapes: \\ -> \, \" -> ", \n -> newline, \t -> tab.
|
||||
s = s.encode("latin-1").decode("unicode_escape")
|
||||
return s
|
||||
|
||||
|
||||
def ext_of(path: str) -> str:
|
||||
base = os.path.basename(path.rstrip("/"))
|
||||
if not base or base in (".", ".."):
|
||||
return "(none)"
|
||||
if "." in base:
|
||||
return "." + base.rsplit(".", 1)[1].lower()
|
||||
return "(none)"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
counts: Counter = Counter()
|
||||
total_rows = 0
|
||||
with open(SRC, newline="", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.rstrip("\n").rstrip("\r")
|
||||
if not line.strip():
|
||||
continue
|
||||
if "\t" not in line:
|
||||
continue
|
||||
rank, path = line.split("\t", 1)
|
||||
path = clean_path(path)
|
||||
total_rows += 1
|
||||
ext = ext_of(path)
|
||||
counts[ext] += 1
|
||||
# order: by count desc, then extension asc
|
||||
ordered = sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))
|
||||
with open(OUT_CSV, "w", newline="", encoding="utf-8") as f:
|
||||
w = csv.writer(f)
|
||||
w.writerow(["rank", "extension", "file_count"])
|
||||
for i, (ext, n) in enumerate(ordered, 1):
|
||||
w.writerow([i, ext, n])
|
||||
total_files = sum(counts.values())
|
||||
md = []
|
||||
md.append("# Extension census")
|
||||
md.append("")
|
||||
md.append("Ranked census of file extensions across the troupe worktree "
|
||||
"(re-derived from `repo_files.tsv` by `extract_extension_census.py`).")
|
||||
md.append("")
|
||||
md.append("| rank | extension | file_count |")
|
||||
md.append("|---|---|---|")
|
||||
for i, (ext, n) in enumerate(ordered, 1):
|
||||
md.append("| %d | %s | %d |" % (i, ext, n))
|
||||
md.append("")
|
||||
md.append("**Total files: %d**" % total_files)
|
||||
md.append("**Unique extensions: %d**" % len(ordered))
|
||||
md.append("")
|
||||
with open(OUT_MD, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(md) + "\n")
|
||||
print("rows=%d total_files=%d extensions=%d"
|
||||
% (total_rows, total_files, len(ordered)))
|
||||
print("top10=%s" % ordered[:10])
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Independent verifier for the extension census.
|
||||
|
||||
Re-derives the census from the SOURCE file `repo_files.tsv` (rank<TAB>path,
|
||||
CRLF) with a standalone loop -- it never imports extract_extension_census --
|
||||
normalizes CRLF line endings, and asserts the resulting ranked (extension,
|
||||
count) table byte-matches `extension-census.csv` produced by that script.
|
||||
|
||||
Exit code 0 = artifact matches re-derivation; 1 = mismatch; 2 = misuse.
|
||||
"""
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
|
||||
REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
SRC = os.path.join(REPO, "repo_files.tsv")
|
||||
ART = os.path.join(REPO, "wizard-work", "ledger", "extension-census.csv")
|
||||
|
||||
PASS = 0
|
||||
|
||||
|
||||
def clean_path(raw):
|
||||
s = raw.strip()
|
||||
if len(s) >= 2 and s[0] == '"' and s[-1] == '"':
|
||||
s = s[1:-1]
|
||||
return s.encode("latin-1", "replace").decode("unicode_escape", "replace")
|
||||
|
||||
|
||||
def ext_of(path):
|
||||
base = os.path.basename(path.rstrip("/"))
|
||||
if not base or base in (".", ".."):
|
||||
return "(none)"
|
||||
if "." in base:
|
||||
return "." + base.rsplit(".", 1)[1].lower()
|
||||
return "(none)"
|
||||
|
||||
|
||||
def re_derivation():
|
||||
counts = {}
|
||||
total = 0
|
||||
with open(SRC, "r", encoding="utf-8", errors="replace") as f:
|
||||
for line in f:
|
||||
line = line.rstrip("\n").rstrip("\r")
|
||||
if "\t" not in line:
|
||||
continue
|
||||
path = clean_path(line.split("\t", 1)[1])
|
||||
total += 1
|
||||
ext = ext_of(path)
|
||||
counts[ext] = counts.get(ext, 0) + 1
|
||||
return sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))
|
||||
|
||||
|
||||
def read_artifact():
|
||||
rows = []
|
||||
with open(ART, newline="", encoding="utf-8") as f:
|
||||
for row in csv.reader(f):
|
||||
rows.append(row)
|
||||
return rows[0], rows[1:]
|
||||
|
||||
|
||||
def main():
|
||||
global PASS
|
||||
header, rows = read_artifact()
|
||||
if header != ["rank", "extension", "file_count"]:
|
||||
print("FAIL: bad header %r" % (header,))
|
||||
return 1
|
||||
expected = re_derivation()
|
||||
if len(rows) != len(expected):
|
||||
print("FAIL: row count artifact=%d rederivation=%d"
|
||||
% (len(rows), len(expected)))
|
||||
return 1
|
||||
for i, ((ext, cnt), row) in enumerate(zip(expected, rows), 1):
|
||||
if row != [str(i), ext, str(cnt)]:
|
||||
print("FAIL: row %d artifact=%r expected=%r"
|
||||
% (i, row, [str(i), ext, str(cnt)]))
|
||||
return 1
|
||||
print("OK: %d rows byte-match re-derivation from repo_files.tsv; header=%r"
|
||||
% (len(rows), header))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user