ADR-0015 and the import. F18's fix: "I don't understand the GROUND card" was never a design gap -- the card explains itself in the edition and we never imported the explanation. THE MEASUREMENT IS THE DECISION, and the gap is bigger than "one file of nineteen". Of the file we DID vendor, the engine reads 5 of 13 columns: title, problem_text, front_rules, reveal_effect and unresolved_effect were discarded at parse time. The cheapest part of this pass costs no new bytes and was sitting in the repo for eight days. And SCN_01 is hardcoded at lib.rs:1824 -- the edition ships FOUR scenarios and the engine has never dealt three of them. Nobody had said so. ADR-0011's revisit condition is measurably absent, so the dependency argument does not get re-run: across Actions, Solutions, Modes and Scenarios there are ZERO doubled quotes and ZERO embedded newlines. The hand reader's only job is comma-in-quoted-field, which it already did. Refusing csv on a measurement rather than on a preference. Vendored Actions, Solutions and Modes -- the text a player reads. Not the production artifacts (BOM, Print_Manifest, Back_Designs, Symbols). NOT Extensions.csv, which names content the designer placed outside the core; importing it would break the claim that this engine plays the edition as printed. It is now known to exist, which was the real risk. One Table reader with four callers, because a per-file copy is how a parser acquires four subtly different bugs. The GROUND card now shows "Regulate. Restore the frame. Decide." with its GR/OU/ND text on demand; Problems show their own titles where a priority number used to be. The load-bearing test asserts the text is a SUBSTRING OF THE VENDORED FILE rather than equal to a Rust literal -- a test comparing against a hardcoded expectation would pass for a hand-copied string, which is the drift this ends. `edition` came out from behind #[cfg(feature = "scenarios")]. It was gated because its only consumer was; the edition is the game's own data and the shipped runtime now reads it. Test machinery and game content are different things and only one of them is optional. And edition-check was written for a single-file world: it compared the first recorded digest against Problems.csv regardless of which file that digest described. It now checks every file both ways -- a vendored file with no digest fails, a digest naming an absent file fails -- and asserts ADR-0015 D3's falsifier directly rather than trusting it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
160 lines
6.9 KiB
Markdown
160 lines
6.9 KiB
Markdown
# ADR-0015: import what a player reads, and read what we already imported
|
|
|
|
status: accepted
|
|
date: 2026-08-06
|
|
decided by: agent, under the standing loop authorization
|
|
tier: M (structural M — imports more of an external dataset under AM-4's
|
|
budgets; chaos d8=1 → no override). Tier M merges survey and decision.
|
|
references: [CB-WP-0028](../workplans/CB-WP-0028-the-table-you-sit-at.md),
|
|
[ADR-0011](ADR-0011-vendor-the-edition.md) (the precedent and its revisit
|
|
condition), [GameDesign.md](../specs/GameDesign.md) §1,
|
|
F18 in [FindingRegister.md](../specs/FindingRegister.md)
|
|
|
|
## Context
|
|
|
|
A player said *"I don't understand the GROUND card."* The card explains
|
|
itself in the edition and the engine never imported the explanation.
|
|
|
|
## The measurements this rests on
|
|
|
|
**Taken before deciding, because ADR-0011's own numbers were computed
|
|
against the wrong budget and the correction is the reason that ADR exists.**
|
|
|
|
**1. The gap is bigger than "one file of nineteen."**
|
|
|
|
| | |
|
|
|---|---|
|
|
| edition files in `ground-game` | **19** |
|
|
| vendored in clay-borg | **1** (`Problems.csv`) |
|
|
| columns in that file | **13** |
|
|
| columns the engine reads | **5** — `scenario_id`, `hidden_priority`, `point_value`, `required_solution`, `visibility` |
|
|
| scenarios in the file | **4** (`SCN_01`…`SCN_04`) |
|
|
| scenarios the engine deals | **1** — `SCN_01`, hardcoded at `lib.rs:1824` |
|
|
|
|
**Every Problem already has a `title` and `problem_text` sitting in a file
|
|
we vendored eight days ago**, and the page shows `Repair 2`. The cheapest
|
|
part of this pass costs no new bytes at all.
|
|
|
|
**2. ADR-0011's revisit condition is not triggered, and that is measured.**
|
|
|
|
ADR-0011 refused the `csv` crate and said the decision would be wrong *"if
|
|
this data ever grows nested quoting, embedded newlines, or multiple
|
|
dialects."* Across every candidate file:
|
|
|
|
| file | rows | fields with `,` | with `"` | with newline |
|
|
|---|---:|---:|---:|---:|
|
|
| Actions | 5 | 12 | **0** | **0** |
|
|
| Solutions | 24 | 5 | **0** | **0** |
|
|
| Modes | 3 | 6 | **0** | **0** |
|
|
| Scenarios | 4 | 2 | **0** | **0** |
|
|
|
|
**Zero doubled quotes, zero embedded newlines.** The hand reader's only
|
|
job is comma-in-quoted-field, which it already does. **The dependency
|
|
argument does not get re-run**, because the condition that would re-open
|
|
it is absent — not because re-running it would be inconvenient.
|
|
|
|
---
|
|
|
|
## D1 — read the columns we already have, first
|
|
|
|
`title`, `problem_text`, `front_rules`, `reveal_effect` and
|
|
`unresolved_effect` are in the vendored file and discarded at parse time.
|
|
They become part of `EditionProblem` and reach the page.
|
|
|
|
**This is the whole of observation 2's Problem half and costs zero new
|
|
dependencies, zero new files and no budget.** It is listed first because
|
|
a pass that imports three new files while ignoring eight columns of the
|
|
file it already has would be solving the interesting problem and not the
|
|
real one.
|
|
|
|
## D2 — vendor `Actions.csv`, `Solutions.csv`, `Modes.csv`
|
|
|
|
These carry the text a player reads:
|
|
|
|
- **Actions** — the five action cards' `title`, `tagline`, `rules_text`.
|
|
The GROUND card's own words are here, and this is the reported defect.
|
|
- **Solutions** — `title` and `microcopy` per card, so a hand shows
|
|
*"Ask What Happened"* rather than `Clarify`.
|
|
- **Modes** — the scoring mode's `title`, `tagline` and `rules_text`, and
|
|
its `scoring_tiebreak`, which T07 needs and which we would otherwise
|
|
have invented.
|
|
|
|
Each vendored with a digest and a provenance line, exactly as
|
|
`Problems.csv` was.
|
|
|
|
**Not vendored:** `BOM`, `Print_Manifest`, `Back_Designs`, `Symbols`,
|
|
`Design_Tokens`, `README`, `metadata` — production artifacts for a
|
|
physical print run, with no meaning to a simulator.
|
|
|
|
**`Extensions.csv` is not imported, and the reason is stated rather than
|
|
assumed:** it names content the designer deliberately placed *outside* the
|
|
core (`not_in_core_reason` is a column). Importing it would put
|
|
non-core content in an engine whose whole claim is that it plays the
|
|
edition as printed. **It is now known to exist**, which was the actual
|
|
risk.
|
|
|
|
**`Relations`, `DARVO`, `Tokens`, `Glossary` are deferred**, not refused:
|
|
they describe mechanisms `GroundRules.md` already encodes as rules, and
|
|
nothing a player reads is missing from the page without them. If T02 finds
|
|
a seat's DARVO stage needs its own words, that is the trigger.
|
|
|
|
## D3 — the hand reader stays
|
|
|
|
Measured above. ~50 lines we own against 17,651 for `csv`, and the
|
|
grammar has not grown.
|
|
|
|
**What changes:** the reader becomes generic over "a vendored CSV with a
|
|
header" instead of being `Problems.csv`-shaped, because it is about to
|
|
have four callers. **A per-file copy is how a parser acquires four subtly
|
|
different bugs.**
|
|
|
|
**Falsifier, restated so it stays live:** if any future edition file
|
|
carries a doubled quote or an embedded newline, this decision is wrong and
|
|
`csv` is the answer. The check is one command and belongs in
|
|
`edition-check.py`.
|
|
|
|
## D4 — where text and rules disagree, that is a finding
|
|
|
|
`GroundRules.md`'s 59 rules were hand-derived from these files. Importing
|
|
the files puts the source beside the transcription for the first time.
|
|
|
|
> **A `rules_text` that contradicts a numbered rule is a register finding
|
|
> — kind `inconsistent` — not a quiet edit of either.**
|
|
|
|
Neither wins automatically: the dataset is authoritative on the *game*,
|
|
but our rule may encode a ruling `ground-game` has since made. The
|
|
register is where that gets resolved, and `ground-game` owns the answer.
|
|
|
|
**This is the most valuable thing the import can produce** and it is
|
|
adversarial to our own work, which is why it is written down before
|
|
anyone looks.
|
|
|
|
## D5 — the scenario stays hardcoded, and that is now visible
|
|
|
|
`SCN_01` at `lib.rs:1824`, one of four. Not changed here: choosing a
|
|
scenario is a setup-surface change (`Setup` has `preset` and `patch`), and
|
|
bundling it into a text-import pass would make both harder to review.
|
|
|
|
**Recorded as an open item rather than left as a surprise** — the engine
|
|
has never played three quarters of the shipped content, and nobody had
|
|
said so.
|
|
|
|
## Consequences
|
|
|
|
- `editions/ground-darvo-r0/` gains three files, each with a digest.
|
|
- `edition.rs` gains a generic reader and four typed views over it.
|
|
- `EditionProblem` gains the text columns already present.
|
|
- `edition-check.py` verifies the new digests and the no-doubled-quotes
|
|
condition D3 rests on.
|
|
- The page can show the game's own words (T02).
|
|
|
|
## What was rejected
|
|
|
|
| rejected | why |
|
|
|---|---|
|
|
| the `csv` crate | its revisit condition is measurably absent (§2) |
|
|
| importing all 19 files | production artifacts have no meaning to a simulator |
|
|
| `Extensions.csv` | deliberately non-core content; importing it would break the as-printed claim |
|
|
| a per-file parser | four copies acquire four subtly different bugs |
|
|
| resolving text-vs-rules conflicts in place | that is a finding, and `ground-game` owns the answer |
|
|
| changing the scenario here | a setup-surface change bundled into a text import makes both harder to review |
|