approve x/image and re-cost the core ceiling

ADR-0040 puts the dependency approval on the record, as hard rule 2 requires: the
standard library decodes JPEG, PNG and GIF but cannot resize, and image/draw
scales only by nearest neighbour, which is visibly wrong on the photographic
downscales this site is made of. Four modules against a cap of six, no transitive
dependencies, and WebP decoding comes along. AVIF still has no decoder anywhere,
so it will pass through untouched.

ADR-0041 raises CORE_LOC_MAX 2000 → 2800. The old figure was costed before any
code existed, for the spine and the render path, and never budgeted what cmd/ will
hold: `check` ~250, `new` ~100, `-dev` ~100, change detection ~100, page cache
~200. On a core already at 1870 that is ~2620 before anything optional, so the gate
was going to fail work nobody would call excess. A costing error corrected, not
discipline loosened.

The ADR and HARNESS.md both say what a *second* raise would mean: that something
belongs in internal/ext/. Two ceilings exist so "core stops growing, ext rises" is
observable, and that stops being true the moment leaves are let into core.
This commit is contained in:
Claude Opus 5
2026-07-31 02:48:52 +06:00
committed by bdeshi
parent c88ca93107
commit 98d0e52936
4 changed files with 44 additions and 2 deletions
+6
View File
@@ -52,6 +52,12 @@ must do — not the theme. `verify.sh` fails if the embedded reference theme cha
changing, because in practice those two drift together — and it fails on a `<script>` tag in that theme,
because a reference theme that grows taste stops being a reference (ADR-0026).
**The core ceiling moved once, on purpose.** `CORE_LOC_MAX` went 2000 → 2800 (ADR-0041) because the original
figure was costed before any code existed and never budgeted what `cmd/` would hold — `check`, `new`, `-dev`,
change detection. Treat a *second* raise as evidence that something belongs in `internal/ext/` instead: the
two ceilings exist so that "core stops growing, ext rises" is observable, and that stops being true the moment
leaves are allowed into core.
**What is staged has to build, not just the working tree.** Every other gate looks at your files; this one
looks at the commit you are about to make, by building a throwaway checkout of the index. It exists because
staging a subset — a changed signature without its caller — produced a commit that did not compile while
+31
View File
@@ -519,3 +519,34 @@ stated wherever a key is documented; and the set of keys must stay declared or `
config, which is the failure the parked cascade already warns about.
Revisit if: a section wants to set a policy for everything beneath it. That is the parked cascade arriving
for real, and its trigger is unchanged: the first section-level override with a reader.
## ADR-0040 — `golang.org/x/image` for resampling and WebP decoding
Date: 2026-07-30 · Status: accepted (human approval on the record, per hard rule 2)
Decision: add `golang.org/x/image` to the allowlist, for `draw` (CatmullRom resampling) and `webp` (decode).
Total modules go from three to four, against a cap of six.
Why: the standard library decodes and encodes JPEG, PNG and GIF but cannot resize — `image/draw` scales only
by nearest neighbour, which is visibly wrong on photographic downscales, and a site whose content *is*
pictures cannot ship that. A hand-rolled box filter is about fifty lines and still worse than CatmullRom on
exactly the material this site has. `x/image` is maintained by the Go team, sibling of the `x/text` already
allowed, and carries no transitive dependencies.
Consequence: cheap — good downscaling and WebP input for one module. Expensive — AVIF still has no decoder in
either the standard library or this module, so AVIF passes through untouched; and image code now has a
dependency that must be checked at each Go release like any other.
Revisit if: the standard library gains a resampler, or AVIF becomes something the site actually publishes.
## ADR-0041 — `CORE_LOC_MAX` 2000 → 2800
Date: 2026-07-30 · Status: accepted
Decision: raise `CORE_LOC_MAX` from **2000** to **2800**. `EXT_LOC_MAX` stays at 2000. The budget continues
to cover `cmd/` plus `internal/{content,render,web}`.
Why: the original figure was costed before any code existed, for "spine, bundles, queries, render, routing,
templates" — and it never budgeted the things `cmd/` will hold. Costing what remains that cannot be a leaf:
`check` ~250, `new` ~100, `-dev` ~100, change detection ~100, the page cache ~200. On top of 1870 that is
~2620 before anything optional, so the ceiling was going to fail on work nobody would call excess. This is a
costing error being corrected, not discipline being loosened.
Consequence: cheap — the gate stops blocking planned core work, and 2800 still binds at roughly one feature's
slack. Expensive — a raised ceiling is a weaker signal than the one it replaces, so the *second* raise should
be treated as evidence that something belongs in `internal/ext/` instead. Features that are leaves must keep
going there: if they land in core, `EXT_LOC` measures nothing and invariant 9 becomes unobservable, which is
the whole reason there are two ceilings.
Revisit if: core approaches 2800. That is the question "what here is not core?" and the answer is a leaf, not
a third raise.
+1
View File
@@ -5,4 +5,5 @@
github.com/yuin/goldmark
golang.org/x/text # NFC normalisation (ADR-0015); collation later if earned
golang.org/x/image # CatmullRom resampling + WebP decode (ADR-0040); no stdlib resizer exists
gopkg.in/yaml.v3 # frontmatter + site declaration (ADR-0020)
+6 -2
View File
@@ -5,7 +5,7 @@
# 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=2000 # cmd/ + internal/{content,render,web} + repo root, non-test .go
CORE_LOC_MAX=2800 # cmd/ + internal/{content,render,web} + repo root, non-test .go (ADR-0041)
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
@@ -13,7 +13,11 @@ DEPS_MAX=6 # total modules in go.mod, direct plus indirect
# 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: spine, bundles, queries, render, routing, templates ~1200-1800 → CORE 2000.
# 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.