testsAndMisc/python_pkg/token_audit/surfaces.py
Krzysztof kuhy Rudnicki 11aea86920 Land the token_audit standing-cost checkup (116 tests, 100% branch coverage)
Answers "what is billed on every turn regardless of use" by measurement
instead of recall, which is the part earlier audits kept getting wrong.

A surface is reported dead only when unused in BOTH windows. One earlier
audit's seven-day dead list included six servers that had been used within
thirty days, so a single window is not evidence. Shares are weighted with
cache-read weight 0.1, so a cached surface is not billed as though it were
re-read in full each turn.

Verified by running it, not just by tests: the report renders over 44,311
turns, putting rules/ at 4,907 tokens (1.77%), MEMORY.md at 4,312 (1.55%),
memories/ at 3,758 (1.35%), skill descriptions at 3,279 (1.18%) and CLAUDE.md
at 2,057 (0.74%), with per-MCP 7d/30d call counts behind each verdict.

The files were found untracked in the tree from an earlier session; every
module is already under the 250-line cap, so nothing needed splitting, and
the package was already at 100% branch coverage, so nothing needed new tests.
This lands the instrument only -- no surface is unregistered on its say-so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 14:33:03 +02:00

158 lines
5.1 KiB
Python

"""Enumerate every context surface that is billed on every turn.
The weekly audit kept missing surfaces — plugins and ``autoMode.environment``
were both found only because the user asked "nothing else?". The fix is that
the list of surfaces lives in code: a surface that is not measured shows up as
an explicit row with ``measured=False`` instead of silently not existing.
Sizes here are *estimates from disk*. Anything that can be A/B'd against a real
process start should be, via :mod:`python_pkg.token_audit.probe`; disk size and
measured prefix cost disagree (skill descriptions are summarised, MCP servers
contribute only tool names), and the measured number is the one to trust.
"""
from __future__ import annotations
from dataclasses import dataclass
import json
from pathlib import Path
CLAUDE_DIR = Path.home() / ".claude"
GLOBAL_CONFIG = Path.home() / ".claude.json"
SETTINGS = CLAUDE_DIR / "settings.json"
# Anthropic's rough byte-to-token ratio for English prose.
BYTES_PER_TOKEN = 4
@dataclass(frozen=True)
class Surface:
"""One always-loaded context component."""
name: str
detail: str
bytes_on_disk: int
measurable: bool = False
@property
def est_tokens(self) -> int:
"""Disk size converted to an approximate token count."""
return self.bytes_on_disk // BYTES_PER_TOKEN
def _tree_bytes(root: Path, pattern: str = "*.md") -> int:
"""Total size of every file under *root* matching *pattern*."""
if not root.is_dir():
return 0
return sum(p.stat().st_size for p in root.rglob(pattern) if p.is_file())
def _json_field_bytes(path: Path, field: str) -> int:
"""Serialized size of one top-level field, or 0 when absent."""
if not path.exists():
return 0
try:
data = json.loads(path.read_text())
except (json.JSONDecodeError, OSError):
return 0
if field not in data:
return 0
return len(json.dumps(data[field]))
def _skill_description_bytes() -> int:
"""Approximate the frontmatter that every skill contributes."""
total = 0
for skill in (CLAUDE_DIR / "skills").glob("*/SKILL.md"):
head = skill.read_text(errors="replace")[:4000]
_, _, rest = head.partition("description:")
total += len(rest.split("\n---", 1)[0]) if rest else 0
return total
def _mcp_names(path: Path, field: str = "mcpServers") -> list[str]:
"""Server names registered in a config file."""
if not path.exists():
return []
try:
return sorted(json.loads(path.read_text()).get(field, {}))
except (json.JSONDecodeError, OSError):
return []
def _enabled_plugins() -> list[str]:
"""Plugins switched on in settings.json."""
if not SETTINGS.exists():
return []
try:
plugins = json.loads(SETTINGS.read_text()).get("enabledPlugins", {})
except (json.JSONDecodeError, OSError):
return []
return sorted(name for name, on in plugins.items() if on)
def _project_mcp_files() -> list[Path]:
"""Project-scoped .mcp.json files under the home directory.
These are invisible to ``--strict-mcp-config``, which is exactly how an
earlier audit under-measured the real baseline by ~2,000 tokens/turn.
"""
return sorted(p for p in Path.home().glob("*/.mcp.json") if p.is_file())
def collect() -> list[Surface]:
"""Enumerate every known billed surface.
Adding a surface here is what makes it appear in the report; the weekly
check walks this list rather than a human's memory of it.
"""
memory_dir = CLAUDE_DIR / "projects" / "-home-kuhy" / "memory"
plugins = _enabled_plugins()
project_mcp = _project_mcp_files()
global_mcp = _mcp_names(GLOBAL_CONFIG)
parked = _mcp_names(CLAUDE_DIR / "mcp-parked.json")
return [
Surface(
"rules/",
"always-on, loaded recursively",
_tree_bytes(CLAUDE_DIR / "rules"),
),
Surface("memories/", "always-on", _tree_bytes(CLAUDE_DIR / "memories")),
Surface(
"CLAUDE.md",
"global instructions",
(CLAUDE_DIR / "CLAUDE.md").stat().st_size
if (CLAUDE_DIR / "CLAUDE.md").exists()
else 0,
),
Surface(
"MEMORY.md",
"auto-memory index",
(memory_dir / "MEMORY.md").stat().st_size
if (memory_dir / "MEMORY.md").exists()
else 0,
),
Surface(
"skill descriptions",
f"{len(list((CLAUDE_DIR / 'skills').glob('*/SKILL.md')))} personal skills",
_skill_description_bytes(),
),
Surface("plugins", ", ".join(plugins) or "none", 0, measurable=True),
Surface(
"global MCP",
f"{len(global_mcp)} active, {len(parked)} parked",
0,
measurable=True,
),
Surface(
"project .mcp.json",
f"{len(project_mcp)} repos (per-project only)",
0,
measurable=True,
),
Surface(
"autoMode.environment",
"injected in auto mode",
_json_field_bytes(SETTINGS, "autoMode"),
),
]