CB-WP-0041 done: ADR-0020 refuses the port, and T02 is why
Some checks failed
ci / check (push) Failing after 3s
Some checks failed
ci / check (push) Failing after 3s
T02 — all chance derives from one root seed. Three chance points, all reading it: the setup deck shuffle, the setup Lead draw, and the reshuffle permutation. The Problems deal is not chance at all. So in extensive-form terms the tree has a single chance node at the root. That test was wrong first, and the mutation caught it. It compared state hashes — and GroundState carries `seed` as a field, so "different seeds differ" was true by construction. Mutating the shuffle away left it green. It now compares the dealt configuration, and the same mutation fails it: a wrong-subject error inside the control written for T02. The reshuffle is a pure function of (seed, round) because K5 requires deterministic replay, where a real table reshuffles independently. That is a modelling restriction, not a defect, and it is now pinned. T03 — commit/reveal checked in both directions: before Reveal each seat sees its own selection and no other; after Reveal the information sets merge, because an encoding that hides forever is not commit/reveal either. T04 — ADR-0020 refuses the EFG port, and the blocker is T02 rather than T01, which inverts what the workplan expected. Perfect recall looked like the risk and is a constraint with a known answer: key on observation histories. Making chance explicit is the expensive one — the reshuffle would become a real chance node and break the K5 purity that every recording, replay bundle and trial-note hash depends on. A port would trade the property this project is built on for one it has never needed. Track B's first move is therefore a question, not a build: take "is exploitability meaningful for a co-operative game with a shared threshold" to OpenSpiel on a toy model, where answering it costs nothing. D4 states what being wrong looks like — OpenSpiel settling on a toy what three rounds of policy sweeps could not — and makes watching for it the next action. Taxonomy §4.1 records the EFG correspondence with the test that checks each row, so a later pass starts from a specification rather than a memory. Chaos window 4 at three declarations. Window 3's verdict is now two windows behind and should be evaluated rather than restated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
81f9339b2d
commit
2806b3acb7
5 changed files with 372 additions and 4 deletions
106
decisions/ADR-0020-we-do-not-build-the-port.md
Normal file
106
decisions/ADR-0020-we-do-not-build-the-port.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# ADR-0020: we do not build an extensive-form port, and here is what to do instead
|
||||
|
||||
status: accepted
|
||||
date: 2026-08-08
|
||||
decided by: agent, under the standing loop authorization
|
||||
tier: M (a decision *not* to create a capability port; creating one would
|
||||
have been L). chaos d8 = 7 → no override. **Declaration 3 of chaos
|
||||
window 4.**
|
||||
references: [CB-WP-0041](../workplans/CB-WP-0041-the-extensive-form-foundation.md),
|
||||
[CB-RES-0009](../research/CB-RES-0009-extensive-form-is-the-lingua-franca.md),
|
||||
[`specs/Positioning.md`](../specs/Positioning.md) §4 Track B,
|
||||
[`simulators/openspiel.md`](../simulators/openspiel.md)
|
||||
|
||||
## Context
|
||||
|
||||
[CB-RES-0009](../research/CB-RES-0009-extensive-form-is-the-lingua-franca.md)
|
||||
found the extensive-form game is the interchange format between
|
||||
describing a game and analysing it, and that clay-borg already has most
|
||||
of one. CB-WP-0041 T01–T03 then asked what is actually true of the
|
||||
engine, and the answers changed the decision.
|
||||
|
||||
## D1 — the three findings this rests on
|
||||
|
||||
**T01. Perfect recall fails on the projection and holds on the history.**
|
||||
22 violations in 44,938 sampled decision points when the information set
|
||||
is taken to be `project(Viewer::Player(seat))`; none when it is the
|
||||
seat's observation history. **`project()` is an observation, not an
|
||||
information state** — OpenSpiel's own `ObservationString` /
|
||||
`InformationStateString` split, found here by measurement.
|
||||
|
||||
**T02. All chance is one root node, and the reshuffle is correlated.**
|
||||
Three chance points, all reading the root seed; the Problems deal is not
|
||||
chance at all. The reshuffle permutation is a pure function of
|
||||
`(seed, round)` **because K5 requires replay to be deterministic**, where
|
||||
a real table would reshuffle independently.
|
||||
|
||||
**T03. Commit/reveal is the EFG simultaneity encoding**, and now checked
|
||||
in both directions rather than assumed.
|
||||
|
||||
## D2 — we do not build an EFG export port
|
||||
|
||||
**Refused, and the reason is T02, not T01.**
|
||||
|
||||
T01 looked like the blocker and is not: it is a *constraint* with a known
|
||||
answer — key information sets on observation histories. That is a
|
||||
specification, and a cheap one.
|
||||
|
||||
**T02 is the blocker.** Making chance explicit means the reshuffle
|
||||
becomes a genuine chance node, and **that breaks the purity that makes
|
||||
every recording in this repo replay**. Our scenarios, the replay bundles,
|
||||
`record.rs`'s round trip, the trial notes' state hashes — all of them rest
|
||||
on chance being a function of state (GameKernel K5).
|
||||
|
||||
> **A port would trade the property this project is built on for a
|
||||
> property it has never needed.** Replay is load-bearing for the evidence
|
||||
> discipline; equilibrium computation is, so far, a research interest.
|
||||
|
||||
**And the port is not the cheap part anyway.** Enumeration is impossible —
|
||||
24 Solution cards give 24! root branches — so any analysis samples chance,
|
||||
which is what our seed sweeps already do.
|
||||
|
||||
## D3 — what we do instead, in order
|
||||
|
||||
1. **Write the mapping down, do not implement it.** The EFG correspondence
|
||||
is now established and tested; it belongs in the taxonomy as a stated
|
||||
relationship, so a later pass starts from a specification rather than a
|
||||
memory.
|
||||
2. **When Track B opens, take the question to OpenSpiel, not our kernel.**
|
||||
Express a *small* GROUND-shaped game against its API and ask whether
|
||||
exploitability says anything useful for a co-operative game with a
|
||||
shared threshold. **That is a question about game theory, not about our
|
||||
engine**, and answering it in our engine would cost the replay property
|
||||
to learn something a toy model answers.
|
||||
3. **If the answer is yes, revisit this ADR.** The cost in D2 is real but
|
||||
it is not infinite: an EFG export that *samples* chance rather than
|
||||
representing it would preserve K5 and might be enough.
|
||||
|
||||
## D4 — what this decision would look like if it were wrong
|
||||
|
||||
**If exploitability turns out to be the instrument that settles design
|
||||
questions** — if it answers *"does ATTACK ever pay"* in a way three review
|
||||
rounds of policy sweeps could not — then refusing the port will look like
|
||||
protecting a process property at the cost of the product's purpose.
|
||||
|
||||
**The tell would be**: OpenSpiel answering, on a toy model, a question our
|
||||
panels have been unable to answer. **Watch for it. That is D3 step 2, and
|
||||
it is deliberately the next thing.**
|
||||
|
||||
## Consequences
|
||||
|
||||
- No EFG port, no OpenSpiel dependency, no equilibrium computation.
|
||||
- **The AM-4 dependency budget is untouched**, which is worth stating
|
||||
because adopting OpenSpiel would have been a large, non-Rust dependency.
|
||||
- Track B's first move is a **question**, not a build.
|
||||
- The three properties T01–T03 established are now regression-tested, so a
|
||||
later port starts from checked ground rather than re-deriving them.
|
||||
|
||||
## What was rejected
|
||||
|
||||
| rejected | why |
|
||||
|---|---|
|
||||
| build an EFG export now | breaks K5 replay purity for a research interest (D2) |
|
||||
| key information sets on `project()` | measured wrong — 22 perfect-recall violations (T01) |
|
||||
| adopt OpenSpiel as an engine dependency | large non-Rust dependency, for a question a toy model answers |
|
||||
| declare Track B blocked | it is not blocked, it is *specified*: the constraint is known and the next step is a question |
|
||||
| say nothing and revisit later | the three findings would be re-derived from memory, which is how this project produces wrong-subject errors |
|
||||
Loading…
Add table
Add a link
Reference in a new issue