Files
goldeneye-pc-port/tools_pc/docs_budget.py
James Dansereau 4b710728bf v0.5.0 playtest fold-in: fog and near-plane clip, crash fixes, polish (D540-D564)
Deck/Windows playtest fixes: fog rework (D540) and RSP-style CPU near-plane
clip with per-vertex N64 fog (D543), with fog recomputed on near-plane-clipped vertices as the RSP does,
so the haze around the player stays steady (D553); colour-combiner clamp for banded walls
(D548); rocket and thrown-item stack overflows (D545, D549); menu
double-trigger mitigation (D541); Dam ending first-shot camera swivel
restored by removing an old port look-at workaround (D552); settings standardisation (D546), live
All unlocked (D547), F10 mouse (D544); static window title and the project
mark (the in-game crosshair shape, site gold) as window/taskbar icon and
favicon (D550). Reference frames re-based
on Windows, Linux and Steam Deck (A/B-confirmed); capture_p7.sh runs on
Windows. Opt-in update check, off by default (D551: one HTTPS request to
GitHub per launch when enabled; winhttp.dll loaded only then; the tag CI
job checks the tag against GE007_VERSION). Release notes, ROADMAP,
internals and security docs updated; tree-hygiene pass.

Refs: D540 D541 D543 D544 D545 D546 D547 D548 D549 D550 D551 D552 D553 D554 D555 D556 D557 D558 D559 D560 D561 D562 D563 D564
2026-10-06 18:35:44 -04:00

174 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""Report the context cost of the docs that every agent session loads.
Usage:
python tools_pc/docs_budget.py # table of per-file budget rows + tier-1 total
python tools_pc/docs_budget.py --json # same data as JSON
python tools_pc/docs_budget.py --toc FILE # markdown TOC (## / ### headings) for FILE
For each tracked doc it prints path, bytes, lines, approx_tokens (bytes // 4),
the per-file budget in approx tokens, and OK/OVER. Missing files are reported
as "missing" and are not an error (docs/HANDOFF.md is optional). It then sums
the "tier 1" set (CLAUDE.md, AGENTS.md, docs/HANDOFF.md, docs/ROADMAP.md)
against TIER1_BUDGET. Exit code is 1 if any file or the tier-1 total is OVER,
else 0.
"""
import argparse
import json
import os
import re
import sys
# Approximate-token budgets for each tracked doc.
BUDGETS = {
"CLAUDE.md": 4000,
"AGENTS.md": 6000,
"docs/HANDOFF.md": 3000,
"docs/ROADMAP.md": 12000,
"docs/porting-notes.md": 60000,
"docs/dev/findings.md": 650000,
"docs/dev/findings-index.csv": 40000,
}
# Files whose approx tokens are summed for the tier-1 total.
TIER1_FILES = ["CLAUDE.md", "AGENTS.md", "docs/HANDOFF.md", "docs/ROADMAP.md"]
TIER1_BUDGET = 25000
def repo_root():
"""Repo root = parent dir of the script's directory."""
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def read_bytes(path):
"""Return (bytes, lines) for a file read as UTF-8 with errors='replace',
or None if the file is missing."""
try:
with open(path, "r", encoding="utf-8", errors="replace") as f:
text = f.read()
except OSError:
return None
return len(text.encode("utf-8")), len(text.splitlines())
def collect_rows():
"""Build the list of row dicts for every tracked doc."""
root = repo_root()
rows = []
for rel in BUDGETS:
full = os.path.join(root, *rel.split("/"))
data = read_bytes(full)
if data is None:
rows.append({
"path": rel,
"bytes": None,
"lines": None,
"approx_tokens": None,
"budget_tokens": BUDGETS[rel],
"status": "missing",
})
else:
nbytes, nlines = data
tokens = nbytes // 4
budget = BUDGETS[rel]
rows.append({
"path": rel,
"bytes": nbytes,
"lines": nlines,
"approx_tokens": tokens,
"budget_tokens": budget,
"status": "OK" if tokens <= budget else "OVER",
})
return rows
def tier1_total(rows):
total = 0
for row in rows:
if row["path"] in TIER1_FILES and row["approx_tokens"] is not None:
total += row["approx_tokens"]
return total
def print_table(rows, t1):
header = f"{'path':<28} {'bytes':>10} {'lines':>8} {'tokens':>9} {'budget':>9} status"
print(header)
for row in rows:
if row["status"] == "missing":
print(f"{row['path']:<28} missing")
else:
print(
f"{row['path']:<28} {row['bytes']:>10} {row['lines']:>8} "
f"{row['approx_tokens']:>9} {row['budget_tokens']:>9} {row['status']}"
)
t1_status = "OK" if t1 <= TIER1_BUDGET else "OVER"
print(f"{'TIER1 TOTAL':<28} {'':>10} {'':>8} {t1:>9} {TIER1_BUDGET:>9} {t1_status}")
def main(argv=None):
parser = argparse.ArgumentParser(
description="Report the context cost of agent-session docs and fail when over budget."
)
parser.add_argument("--toc", metavar="FILE", help="print a markdown TOC for FILE")
parser.add_argument("--json", action="store_true", help="print JSON instead of the table")
args = parser.parse_args(argv)
if args.toc:
return print_toc(args.toc)
rows = collect_rows()
t1 = tier1_total(rows)
if args.json:
payload = {
"rows": rows,
"tier1": {"total_tokens": t1, "budget_tokens": TIER1_BUDGET,
"status": "OK" if t1 <= TIER1_BUDGET else "OVER"},
}
print(json.dumps(payload, indent=2))
else:
print_table(rows, t1)
over = any(r["status"] == "OVER" for r in rows) or t1 > TIER1_BUDGET
return 1 if over else 0
def github_anchor(heading):
"""GitHub-style anchor: lowercase, strip non-alnum/space/hyphen, spaces -> hyphens."""
text = heading.lower()
text = re.sub(r"[^a-z0-9 \-]", "", text)
return text.replace(" ", "-")
def print_toc(path):
"""Print a markdown TOC of '## ' / '### ' headings, skipping fenced code blocks."""
try:
with open(path, "r", encoding="utf-8", errors="replace") as f:
lines = f.read().splitlines()
except OSError as e:
print(f"error: cannot read {path}: {e}", file=sys.stderr)
return 1
in_fence = False
for line in lines:
if line.lstrip().startswith("```"):
in_fence = not in_fence
continue
if in_fence:
continue
if line.startswith("### "):
heading = line[4:].strip()
print(f" - [{heading}](#{github_anchor(heading)})")
elif line.startswith("## "):
heading = line[3:].strip()
print(f"- [{heading}](#{github_anchor(heading)})")
return 0
if __name__ == "__main__":
# Headings contain non-ASCII (arrows, em dashes); a cp1252 console can't print them.
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8")
sys.exit(main())