diff --git a/decisions/ADR-0004-am4-ratification.md b/decisions/ADR-0004-am4-ratification.md new file mode 100644 index 0000000..1223b9a --- /dev/null +++ b/decisions/ADR-0004-am4-ratification.md @@ -0,0 +1,88 @@ +# ADR-0004: ratify AM-4a and AM-4b + +status: accepted +date: 2026-07-31 +decided by: maintainer (Bernd Worsch), 2026-07-31 +tier: S (structural S — ratifies an existing target, creates no capability; chaos d4=3) +supersedes: nothing; discharges the open item raised by CB-WP-0003 T07 +references: [GameKernel.md](../specs/GameKernel.md) §4, +[InnerLoop.md](../specs/InnerLoop.md) §Step 4 (correction vs retarget), +`history/260731-inner-loop-rule-audit.md` + +## Why this ADR exists + +CB-WP-0003 T07 added a mechanical test separating a **correction** (the +instrument disproved the target; the implementation did not change) from a +**retarget** (the same commit moved both the target and the code it +measures). AM-4a/AM-4b failed that test: they were set at 250,000 and +350,000 in commit `4be6e02`, by the implementer, after seeing the measured +246,250 — and that commit also changed the feature gating the metric +measures. + +The reasoning was recorded at the time and is defensible. The *structure* +was not, and the audit flagged both targets as unratified: `make +dep-weight` has been enforcing thresholds no reviewed decision stood +behind. + +## Decision + +**AM-4a (≤ 250,000 lines, shipped runtime) and AM-4b (≤ 350,000 lines, +dev toolchain) are ratified as written.** No values change. + +## The old target, and why it was abandoned + +AM-4 originally read **≤ 20 transitive crates**, set against +boardgame.io's 120 npm packages. Retired for two measured reasons: + +1. **Unreachable without undoing this spec's own contracts.** K5 (seeded + ChaCha) and K7 (SHA-256) cost 12 crates between them. The measured + ladder showed nothing reached 20 except reimplementing one of those + primitives — trading an audited cryptographic implementation for a + scoreboard number. +2. **Crate count does not compare across ecosystems.** Rust splits crates + far more finely than npm, so the original 33-vs-120 comparison + flattered us while the ≤20 target punished us, for the same reason. + +## The measurement that motivated the change + +At the time of the retarget, `make dep-weight`: + +| configuration | crates | third-party LOC | +|---|---|---| +| shipped-runtime (`--no-default-features`) | 23 | **246,250** | +| dev-toolchain (default features) | 29 | **317,021** | +| own source | — | 3,443 | + +## Why these targets bind on future work rather than merely passing present work + +This is the question T07 requires an ADR to answer, and it is the reason +ratification is defensible rather than a rubber stamp. + +- **AM-4a leaves 3,750 lines of headroom — 1.5%.** That is roughly one + small crate. Any dependency added to the shipped runtime breaches it + almost immediately, which is the intended behaviour: the shipped runtime + is meant to be effectively frozen, and the target enforces that a new + runtime dependency is a decision someone must argue for, not a default. +- **AM-4b leaves 32,979 lines — 10.4%.** Deliberately looser. The dev + toolchain is where scenario YAML, benchmarking, and future tooling land, + and it does not ship to a player. It should be able to absorb one + moderate dependency without a spec change, and not two. +- **Both are ceilings on a quantity that only grows by choice.** Nothing + drifts a project across these thresholds; only adding a dependency does. + A target that can only be breached deliberately is a target that binds. + +**What would falsify this ratification:** if a future pass finds itself +raising AM-4a to accommodate a dependency it wanted, that is the failure +mode the ceiling exists to catch, and the answer is a new ADR arguing for +the dependency — not a quiet retarget. + +## Consequences + +- The open item in `history/260731-inner-loop-rule-audit.md` is discharged. +- `make dep-weight` continues to fail the build on breach, now backed by a + reviewed decision. +- AM-4c (own source per 100k third-party lines) remains **reported, not + targeted**, and is unaffected. +- Precedent: this is the first ADR written under the correction/retarget + test. Future retargets follow this shape — old target, the measurement, + and an argument about *future* binding rather than present passing. diff --git a/history/260731-inner-loop-rule-audit.md b/history/260731-inner-loop-rule-audit.md index 13999eb..cc9f56c 100644 --- a/history/260731-inner-loop-rule-audit.md +++ b/history/260731-inner-loop-rule-audit.md @@ -136,12 +136,12 @@ evidence files. ## Open items raised by this audit -- **AM-4a / AM-4b are unratified retargets.** Measured at 246,250 and set - at 250,000 in the same commit, by the implementer, with the - implementation changing in that commit too — a retarget under the test - added to InnerLoop §Step 4 by T07, not a correction. They must be - ratified by ADR or changed. Until then `make dep-weight` is enforcing a - target no reviewed decision stands behind. +- ~~**AM-4a / AM-4b are unratified retargets.**~~ **Discharged + 2026-07-31** by [ADR-0004](../decisions/ADR-0004-am4-ratification.md), + ratified by the maintainer. Values unchanged; the ADR supplies the + future-binding argument the test requires (AM-4a leaves 1.5% headroom, + AM-4b 10.4%, and both measure a quantity that only grows by deliberate + choice). ## Class coverage — where the gaps are diff --git a/specs/GameKernel.md b/specs/GameKernel.md index dad7634..9ba10ef 100644 --- a/specs/GameKernel.md +++ b/specs/GameKernel.md @@ -135,7 +135,10 @@ Command (actor-tagged intent) ## 4. Acceptance metrics -**On AM-4's retarget (2026-07-31).** AM-4 originally read "≤20 +**On AM-4's retarget (2026-07-31).** *Ratified by +[ADR-0004](../decisions/ADR-0004-am4-ratification.md) on 2026-07-31; the +headroom argument for why these ceilings bind on future work lives there.* + AM-4 originally read "≤20 transitive crates", set against boardgame.io's 120 npm packages. That target was retired for two measured reasons. First, it was unreachable without undoing this spec's own contracts: K5 (seeded ChaCha) and K7