ADR-0011 decided it: vendor the CSV with a checked digest, read it with a ~50-line reader, and let the hashes move. The declaration's constraint was measured against the WRONG BUDGET. It said a CSV crate costs 21,613 against AM-4a's 3,798 of headroom, '5.7x over, settled by measurement'. But setup and problem_priorities are cfg(scenarios) and are not in the shipped runtime at all, so AM-4a never sees them. Against AM-4b, csv costs 17,651 against 19,742 -- it FITS, with 2,091 to spare. It is refused anyway, on proportion: 89% of the budget's remaining capacity to read 20 rows. The revisit condition is stated (nested quoting, embedded newlines, multiple dialects). GR-S01 now deals Surface + hidden 1..=k as ruled, with edition values and suits. Measured: 6/9/12 available against thresholds 5/7/9 -- the game is winnable at every seat count, which is what the maintainer could not do. gd0001 is INVERTED, not deleted, and now also asserts the 6/9/12 so a deal that is reachable for the wrong reason still fails. Blast radius was scenario expectations, exactly as the ADR predicted: no scenario pinned a hash and no bundle is committed. Six scenarios and two unit tests updated, each with a note. gr-e01-threshold-unreachable-2p is RENAMED to -reachable- and rewritten as the non-provisional import check ground-game asked for by name. gr-e03's setup was restructured, not just renumbered: with values 2,2,2 its personal-edge test would have tied three ways and asserted nothing. BLOCKING: AM-7 fails at median 0.845 against its 0.9 floor. Isolated across three runs -- 3 problems + stand-in 0.97, 3 problems + edition 0.909, 4 problems + edition 0.845. State is BOUNDED (proven: identical after 5k and 100k events), so this is not the unbounded-growth defect AM-7 exists to catch; it is a bigger working set streaming a long log. Whether AM-7's floor is still right for a larger aggregate is a spec question and lowering it requires an ADR, so it is not being tuned here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
118 lines
5.3 KiB
Markdown
118 lines
5.3 KiB
Markdown
# 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.
|