clay-borg/decisions/ADR-0004-am4-ratification.md

105 lines
5.1 KiB
Markdown
Raw Normal View History

CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
> **Superseded in part, 2026-08-03 (CB-WP-0019 T01/T02).** This ADR
> ratified AM-4b at ≤350,000 against a graph measuring 317,021 — but that
> graph was **one package with no dev edges**, blind to 28 crates and
> 408,237 lines. AM-4b now asks *what a contributor acquires*
> (`--workspace --edges normal,dev`, proc-macros counted) and its target is
> **745,000**. The reasoning here still stands; the scope it was applied to
> did not. See `specs/GameKernel.md` §5c.
# ADR-0004: ratify AM-4a and AM-4b
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target ADR-0008, tier M (survey and ADR merged). D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it found a third defect, deeper than the two this pass was declared on. Re-deriving batching from the raw transcripts, independently of cb-cost: CB-WP-0011 pass 54 with tools 0 batched 0.0% gap -> next decl 16 with tools 6 batched 37.5% CB-WP-0012 pass 86 with tools 0 batched 0.0% gap -> next decl 10 with tools 1 batched 10.0% CB-WP-0013 so far 10 with tools 0 batched 0.0% Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the 20% floor. Batching needs two calls whose inputs are known at once — orientation work. Implementation consumes each step's result before the next. SH-3's window is since the last commit, which during a pass is always implementation. The metric could not read above ~0% in the window it was gated on. A floor the window structurally excludes is not a target. This pass's own declaration was also wrong: it claimed batching "has got worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different behaviour. Withdrawn — the same class of error, in the pass written to correct it. Not retargeting to match the measurement: the floor was not moved to 6%, the gate was removed on an argument about what the quantity is worth. The number is still reported; only the verdict is gone. D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250. The target moves down with it, 250,000 -> 161,000, so the correction hands back essentially nothing (headroom 3,750 -> 3,798). Three controls: the exclusion drops exactly the five expected crates, only removes and never adds, and is not a no-op. The DFD gate then caught the follow-on it exists for — three historical documents carrying live fact tags for a number that had changed. Not rewritten; untagged, with a supersession banner. AM-4b is deliberately not corrected: its proc-macro share is unmeasured. gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its first caught entry by forcing SH-3's re-justification, and the registry has no silent gates left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 07:30:14 +02:00
> **Superseded measurement (ADR-0008 D2/D3, 2026-08-02).** The AM-4a
> figures below were taken with an instrument that counted proc-macro
> crates — 89,048 lines, 36.2% — which run in the compiler and never
> reach a binary. Corrected, the same tree measures **157,202** against
> a target moved to **161,000**. The numbers below are left as the
> record of what was measured then, and are no longer live facts.
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 |
|---|---|---|
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target ADR-0008, tier M (survey and ADR merged). D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it found a third defect, deeper than the two this pass was declared on. Re-deriving batching from the raw transcripts, independently of cb-cost: CB-WP-0011 pass 54 with tools 0 batched 0.0% gap -> next decl 16 with tools 6 batched 37.5% CB-WP-0012 pass 86 with tools 0 batched 0.0% gap -> next decl 10 with tools 1 batched 10.0% CB-WP-0013 so far 10 with tools 0 batched 0.0% Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the 20% floor. Batching needs two calls whose inputs are known at once — orientation work. Implementation consumes each step's result before the next. SH-3's window is since the last commit, which during a pass is always implementation. The metric could not read above ~0% in the window it was gated on. A floor the window structurally excludes is not a target. This pass's own declaration was also wrong: it claimed batching "has got worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different behaviour. Withdrawn — the same class of error, in the pass written to correct it. Not retargeting to match the measurement: the floor was not moved to 6%, the gate was removed on an argument about what the quantity is worth. The number is still reported; only the verdict is gone. D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250. The target moves down with it, 250,000 -> 161,000, so the correction hands back essentially nothing (headroom 3,750 -> 3,798). Three controls: the exclusion drops exactly the five expected crates, only removes and never adds, and is not a no-op. The DFD gate then caught the follow-on it exists for — three historical documents carrying live fact tags for a number that had changed. Not rewritten; untagged, with a supersession banner. AM-4b is deliberately not corrected: its proc-macro share is unmeasured. gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its first caught entry by forcing SH-3's re-justification, and the registry has no silent gates left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 07:30:14 +02:00
| shipped-runtime (`--no-default-features`) | 23 | **246,250** | <!-- historical: measured under the pre-ADR-0008 instrument; not a live fact -->
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires The two AM-4 budgets had the SAME scope -- one package, no dev edges -- while claiming to bound different things. AM-4b now measures the workspace with dev edges: 57 crates / 725,258 lines where it read 29 / 317,021, having been blind to 28 crates and 408,237 lines, more source than its own target. Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a, applied to a number that grew because the instrument was repaired, not because anything was added. The target moved to fit the measurement. T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose. AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is acquired, and ADR-0007 D3's acquisition rule counts what the build fetches -- 'it does not ship' is no answer to 'we downloaded it'. When the rules disagree, the question each budget asks decides. Measured share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's refusal to borrow the ratio was right by more than a factor of two. Caught by this project's own earlier work twice: the mutation find-string went stale and --self-test reported it BUILD-FREE (the check CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate caught facts.toml carrying the old numbers. CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings. A dated record asserting a CURRENT value is a category error, so those occurrences are marked as-measured instead of retro-edited, and ADR-0004 gains a supersession note. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:04:54 +02:00
| dev-toolchain (default features) | 29 | **317,021** | <!-- as-measured 2026-07-31; AM-4b was rescoped by CB-WP-0019, see GameKernel 5c -->
| 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.