# 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=2850 # cmd/ + internal/{content,render,web} + repo root, non-test .go (ADR-0041, ADR-0065) EXT_LOC_MAX=2000 # internal/ext/ — composition, grows after the core freezes FILE_LOC_WARN=500 # any single .go file — advisory FUNC_LOC_WARN=60 # any single function — advisory DEPS_MAX=6 # total modules in go.mod, direct plus indirect 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. # # 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 — `docs/README.md`'s compression contract governs which of the two you are doing.