3.8 KiB
ADR-0002: Game-state kernel — survey approval and implementation decision
Date: 2026-07-31 Status: accepted Capability: game.kernel.authoritative-state Inputs: research/CB-RES-0001-game-kernel.md (approved), history/260731-game-kernel-{research,challenge,response}.md
Approval (InnerLoop step 2)
The CB-RES-0001 survey is approved. It passed one round of adversarial review: the challenge found one blocking overclaim (degradation attribution) and three significant gaps (memory methodology, omitted candidates OpenSpiel/Ludii, unsourced D3 ceiling); all were resolved with new measurements or corrections, none overturned the comparative conclusions. The candidate set is judged adequate; the baselines are trustworthy within their stated provenance (measured vs cited vs estimated), with the event-sourcing ceiling explicitly parity-capped.
Benchmark-to-beat, named: boardgame.io 0.50.2 per the survey's baseline table (throughput ~1,100–1,900 moves/s degrading with history in every configuration; 120 deps/37 MB; ~36-LOC declarative game definition), plus the stipulated engineering target of ≥100,000 applied events/s with flat scaling (@100k within 10% of @5k) and bit-identical replay.
Decision (InnerLoop step 3): reimplement, assimilating patterns
Build the Clay-Borg semantic kernel as our own Rust implementation
(cb-kernel + cb-events + cb-game-runtime) — not a wrapper around any
surveyed system. Per the Clay-Borg rule, we own the semantics; what we
assimilate from the field is patterns, each with a named source:
| Assimilated pattern | From | Into |
|---|---|---|
| Declarative game definition (setup/moves/phases as data + pure functions) | boardgame.io | game-package rules API |
| Tooling-enforced determinism (not convention) | Rune | seeded RNG service, denied ambient time/random, replay double-run check in the scenario runner |
| Command → validate → events → fold, snapshots bound replay | event-sourcing (cqrs-es pattern) | kernel mutation pipeline |
| Information-state framing for imperfect information | OpenSpiel | per-player projection model |
| Hand-zone / object-visibility semantics | TTS (pattern only) | tabletop layer, later |
Rejected alternatives: assimilate boardgame.io (inactive, JS-bound, history-degrading in best config — fails D2/D3/D4); build on OpenSpiel (right semantics, wrong layer — research kernel without projection/ networking/snapshot surface, heavyweight C++/Python boundary); ECS as kernel (bevy_ecs stays in the world layer per the blueprint).
Expected advantage per dimension (honest trades)
- D3 speed: better. Flat per-event cost with snapshots; the 100k/s floor. Declared caveat: part of the margin over boardgame.io is language choice; the commitment that matters is flat scaling, and the event-sourcing comparison stays at parity until a Rust comparator is measured.
- D2 weight: better. Target ≤20 transitive crates for the headless kernel (vs 120 npm packages), measured by M-D2-DEP/M-D2-LOC/M-D2-BLD.
- D1 specification: parity, aiming better. Match boardgame.io's declarative compactness on the synthetic workload (≤~40 LOC equivalent); surpass via rule-to-scenario traceability (M-D1-COV), which no candidate has. Declared trade: we do not attempt Ludii/GDL-class generality — one game family first, canon only after a second concrete use.
- D4 optionality: better. Port pattern with null/reference impls from day one, capability boundary WIT-expressible later, zero foreign types in canonical interfaces (M-D4-LEAK=0). No surveyed candidate offers this.
Gate
Per InnerLoop, no kernel implementation code existed before this ADR. Next steps: T05 (GROUND rules spec, derived from ground-game), T06 (kernel spec with acceptance metrics tied to these baselines), T07 (workspace + harness), T08 (code loop).