clay-borg/decisions/ADR-0002-game-kernel.md

71 lines
3.8 KiB
Markdown
Raw Normal View History

# 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,1001,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).