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>
5.3 KiB
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, ADR-0007 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.
gd0001is inverted, not deleted — it is the record of why the game became winnable.- If ground-game revises
r0in place, the digest check fails loudly. Per GROUND-WP-0002 T01's proposed contract,point_valueandrequired_solutionmay not change within a revision; this is the mechanism that notices if they do.