# ADR-0011: vendor the edition, read it by hand, and let the hashes move status: accepted date: 2026-08-04 decided by: agent, under the standing loop authorization tier: M (structural M — adds or refuses an external dependency and changes how a game is set up; chaos d8=7 → no override). Tier M merges survey and decision into one document, which this is. references: [CB-WP-0021](../workplans/CB-WP-0021-import-the-edition.md), [ADR-0007](ADR-0007-render-html-not-a-port.md) D3 (the acquisition rule), GROUND-WP-0002 T01 and GROUND-WP-0004 (ground-game's rulings) ## Context `editions/ground-darvo-r0/Problems.csv` is authoritative (ground-game, 2026-08-03) and the engine has been inventing Problem values and suits. GR-S01's deal was then ruled (2026-08-04): **Surface always ∪ hidden `1..k`**, k = 2/3/4, giving available points **6 / 9 / 12** — which holds *only* with the real values. ## Correction: the constraint was measured against the wrong budget **CB-WP-0021's declaration said a CSV crate costs 21,613 lines against AM-4a's 3,798 of headroom — "5.7× over, settled by measurement rather than preference."** `setup` and `problem_priorities` are `#[cfg(feature = "scenarios")]`. **They are not in the shipped runtime at all**, so AM-4a never sees them and never would have. The budget that applies is AM-4b, and measured against *its* graph: | | lines | |---|---:| | AM-4b headroom (745,000 − 725,258) | **19,742** | | `csv` marginal cost (`csv` + `csv-core`; `ryu`, `itoa`, `memchr` already present via `serde_json`) | **17,651** | **It fits, with 2,091 lines to spare.** The declaration's confident "settled by measurement" was measurement of the wrong thing — the third premise this pass has had to correct, and the second where a real number was computed against a mis-chosen denominator. ## Decision 1 — refuse `csv`, on proportion rather than impossibility It fits and it is still refused, and the distinction matters because the argument has to survive someone re-running the numbers. **17,651 lines is 89% of everything AM-4b has left, to read 20 rows.** The next dependency after it would have 2,091 lines to live in. A hand-rolled reader for this grammar is ~50 lines we own. INTENT's rule is *"assimilate the implementation"* — but that is about **mature optimized libraries** for hard problems. Splitting quoted CSV fields is not one, and `Problems.csv` is 20 rows read once at setup. Taking a general parser here would spend the budget's remaining capacity on the easiest problem we have. **If the data grows into something a hand reader should not own — nested quoting, embedded newlines, multiple files with differing dialects — this decision is wrong and `csv` is the answer.** That is the condition to revisit under, stated now rather than left to taste. ## Decision 2 — vendor the file, with a checked provenance `ground-game` is a separate repository. Two options: | | cost | |---|---| | **sibling checkout** | the build depends on a path that may not exist. CI runs `rust:1.97` with this repo only, so `make all` would fail or silently skip — and a silent skip is the class this project has found seven times | | **vendor a copy** | clay-borg carries content it does not own, and a stale copy is worse than no copy | **Vendored**, at `editions/ground-darvo-r0/Problems.csv`, with a `PROVENANCE` note naming the upstream repo, path and revision. The staleness answer is a **committed digest of the upstream file**. A check compares it when `../ground-game` is present, and reports **`upstream not checked out`** as a distinct outcome when it is not — never a pass. That is the shape ADR-0009 used for `node`: an absent thing is reported absent, not treated as satisfied. **Acquisition rule (ADR-0007 D3):** this is content the build causes to be present, and it is ours now. It is not third-party *code* and does not enter AM-4, but the provenance note is what stops it becoming unattributed. ## Decision 3 — the hashes move, and nothing pins them Problem values and suits enter `GroundState`, which is hashed (K7). The declaration called this *"the reason the ADR exists."* Measured: | | | |---|---| | scenario files pinning a state hash | **0** | | replay bundles committed | **0** | | scenarios asserting on `problems.N.*` | **10 of 25** | **So the feared blast radius is not there.** K8's double-run compares two runs of the same build; AM-7's probe compares segments within one run; `replay-test` generates its bundle at run time. All are self-consistent and survive a content change by construction. What breaks is **scenario expectations** — which is exactly what *should* break when the content changes, and is why they are written as `expect` blocks rather than hashes. **No hash is grandfathered and none is recorded as "was".** A recorded hash that outlives the content it describes is a lie with a timestamp. ## Consequences - The deal fix and the import land **together**. The ruled 6/9/12 holds only with real values; the same deal with the stand-in gives 6/10/15, a game nobody ruled on. - `gd0001` is **inverted, not deleted** — it is the record of why the game became winnable. - If ground-game revises `r0` in place, the digest check fails loudly. Per GROUND-WP-0002 T01's proposed contract, `point_value` and `required_solution` may not change within a revision; this is the mechanism that notices if they do.