Files
khosra/scripts/budgets.env
T
bdeshiandClaude Opus 5 ec6e9838f0 rename docs/ to harness/, and reserve docs/ for the reader
docs/content-model.md opens with "Engine specification". It is also where the
rule lives that a leading underscore makes a file unaddressable — and the human
who owns this site did not know that rule, because nothing in this repository is
addressed to an author. Twelve documents named docs/ while being exclusively
about building the parser is a signpost pointing at the wrong room.

Naming the directory for its audience makes the gap visible instead of hiding it.
docs/ is now reserved and deliberately absent: an empty docs/ is an honest
statement that end-user documentation does not exist, where docs/ full of parser
specs was a claim that it did.

HARNESS.md stays at the root. Root holds the three entry points — README.md for a
human, CLAUDE.md for an agent, HARNESS.md for whoever maintains the machine — and
harness/README.md is the map of the directory, so moving the guide inside would
have collided with it for nothing.

Mechanical and wide: 100 path references across 24 files. Every verify.sh gate
that names a doc by path, the directory lists the dangling-path and ADR-number
gates scan, surface.sh's output target, the Makefile, CLAUDE.md's read order, the
skill, four commands, and two Go package comments. A first pass with a shell loop
silently edited only four files and the rest still said docs/; the fix was to
write the file list out and check the remaining count was zero rather than trust
the loop's exit status.

No rule, threshold, gate or obligation moved — this is a rename, and the gates
demonstrated it twice: they stayed green on the new paths, and the ADR-number gate
caught ADR-0082 before the entry existed.

Deferred, both on the human's call: the end-user documentation site itself, which
wants its own decision about where it lives and whether its claims are gated; and
moving examples/ under docs/, since demo-site is a live site root that verify.sh,
the coverage test and make demo all point at, and moving it would couple a rename
to a design nobody has made.

31 files, +146/-106.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 20:11:06 +06:00

39 lines
3.1 KiB
Bash

# Growth budgets. `_MAX` fails verify.sh; `_WARN` prints and moves on.
# Raising a _MAX needs an ADR stating old and new values. Growth requires a signature.
#
# Only whole-system budgets fail. A hard per-file limit is the one gate whose cheapest fix makes the
# code worse — sharding a coherent file into a `_helpers.go` turns it green while creating the package
# CLAUDE.md rule 3.6 bans. Total mass cannot be gamed by moving code between files; file length can.
CORE_LOC_MAX=3000 # cmd/ + internal/{content,render,web} + repo root, non-test .go (ADR-0041, ADR-0065, ADR-0074)
EXT_LOC_MAX=3500 # internal/ext/ — composition, grows after the core freezes (ADR-0074)
FILE_LOC_WARN=500 # any single .go file — advisory
FUNC_LOC_WARN=60 # any single function — advisory
DEPS_MAX=9 # total modules in go.mod, direct plus indirect (ADR-0074)
CLAUDE_LOC_MAX=150 # CLAUDE.md only — the one file billed on every turn (ADR-0053)
# Two ceilings because "the core stops growing after Arc 2" (architecture.md invariant 9) is only an
# invariant if something measures it: post-freeze CORE holds and only EXT rises.
# Costed, not round, and re-costed once (ADR-0041): the first figure covered spine, bundles, queries,
# render, routing and templates (~1200-1800 → 2000) but never budgeted what cmd/ would hold. Adding `check`
# ~250, `new` ~100, `-dev` ~100, change detection ~100 and the page cache ~200 to a core already at 1870
# gives ~2620 → CORE 2800. A second raise is evidence something belongs in internal/ext/, not evidence the
# number is still too small.
# Feeds, sitemap, OpenGraph, shortcodes, image sizing, galleries, paging, indieweb ~900-1200 → EXT
# 2000, deliberately loose since that is where growth belongs. Reaching CORE asks what to delete;
# reaching EXT asks whether a template would have done it — only .go lines count here.
# Raised a second time, 2800 → 2850 (ADR-0065), for eight lines of theme contract. ADR-0041 said to read a
# second raise as evidence something belongs in `ext`: it is, and the candidates are `feed.go` and
# `discover.go`, which cannot move until a feature can own a route. That is the registry's trigger, not this
# feature's problem, and the honest fix was not to pretend the contract fits.
#
# Raised a third time, and this one is different: 2850 → 3000 core, 2000 → 3500 ext, 6 → 9 modules, all
# signed off in advance of a list of features rather than in response to one that arrived (ADR-0074). A
# ceiling raised on evidence is a measurement; a ceiling raised on intent is a budget, and this is the second
# kind. `ext` was the binding one — 1975 of 2000 with a syntax-highlighting feature still to write.
#
# CLAUDE_LOC_MAX is a different kind of budget: every other ceiling here bills once, when someone reads
# the code, while CLAUDE.md is re-sent on every turn of every session. 150 leaves ~20 lines of headroom
# over the current file. Reaching it means moving detail to the doc that owns the topic, never deleting
# a rule to fit — `harness/README.md`'s compression contract governs which of the two you are doing.