clay-borg/research/CB-RES-0001-game-kernel.md

154 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CB-RES-0001: game-state kernel
capability: game.kernel.authoritative-state
status: draft # becomes approved only after adversarial review (T04)
tier: L (structural L, chaos roll pending at T04 declaration — see history trail)
runnable-baseline: invoked — harness in research/CB-RES-0001-harness/boardgame-io/
Survey of the best existing implementations of a **turn/phase game-state
kernel**: deterministic authoritative state, command → validation → events,
simultaneous commit/reveal, hidden information, replay. Conducted
2026-07-31; research trail in
[history/260731-game-kernel-research.md](../history/260731-game-kernel-research.md).
---
## Candidates
### 1. boardgame.io 0.50.2 (JS/TS) — measured
The most direct comparator: a declarative turn-based game engine.
- **Data model:** single plain-object `G` (game state) + framework `ctx`
(turn/phase bookkeeping). Game defined declaratively: `setup`, `moves`,
`phases`, `turn.stages`.
- **Mutation:** moves are reducer functions run through Redux + Immer;
mutate a draft, framework produces immutable next state and appends to an
action **log** (basis for time travel).
- **Determinism/replay:** seeded RNG via `random` plugin; log + seed give
replay and time travel. Measured: same seed → identical state hash across
runs; different seed diverges. ✅
- **Hidden information:** `playerView` projection (e.g. `STRIP_SECRET`) —
server strips secret state per player.
- **Simultaneous actions:** `activePlayers` stages give simultaneous move
windows; no built-in cryptographic commit/reveal — commitment is plain
state the server can see (fine for server-authoritative, nothing for
peer settings).
- **Maturity:** 12.4k GitHub stars, but **inactive** — last npm release
0.50.2 ≈ 4 years ago (Snyk: "maintenance: Inactive").
- **Measured performance** (our harness, synthetic 3-player GROUND-shaped
commit/reveal workload, Node v24, this machine `bnt-lap001`):
| applied moves | moves/s | elapsed | RSS |
|---:|---:|---:|---:|
| 5,000 | 1,930 | 2.6 s | 224 MB |
| 10,000 | 1,605 | 6.2 s | 229 MB |
| 20,000 | 870 | 23.0 s | 271 MB |
| 100,000 | did not finish in 300 s | — | — |
**Per-move cost grows with history length** (log accumulation + state
pipeline): throughput halves as move count doubles — superlinear total
cost. This is architectural (unbounded redux log per client), not a
tuning artifact.
- **Weight:** 120 transitive npm packages, 37 MB `node_modules`, core
package 3.9 MB.
### 2. Tabletop Simulator scripting model (Lua) — cited
The dominant commercial virtual tabletop; reference for *tabletop
semantics*, not a rules kernel.
- **Data model:** none authoritative — game state *is* the physical scene;
Lua state serialized as strings into the save JSON (`onSave`/`onLoad`).
- **Mutation:** imperative Lua in a Global script + per-object scripts with
event hooks; **no move validation or rules engine** — rules are social,
physics is primary (sandbox mode in Clay-Borg terms).
- **Determinism/replay:** none. Hidden info via hand zones (engine feature,
not a projection model).
- Valuable as the pattern source for object-attached behavior and hand
zones; architecturally the anti-model for an authoritative kernel.
### 3. Rune SDK (JS) — cited
Modern (active, 20242026) deterministic multiplayer engine for casual web
games.
- **Data model/mutation:** pure `logic.js` — game state + action functions,
statically checked for nondeterminism (mutation escape, `Math.random`
patched deterministic).
- **Sync:** predict-rollback: all clients + server simulate the same
deterministic logic; server authoritative, clients predict. Strongest
determinism *discipline* of the candidates — enforced by tooling, not
convention.
- **Limits:** platform-bound (Rune's hosted app ecosystem), not an
embeddable open kernel; no phase/stage framework, hidden-information
projection, or event-sourced replay surface comparable to boardgame.io.
### 4. Event-sourcing kernels (Rust `cqrs-es` pattern / EventStoreDB) — cited
The general-purpose form of our mutation pipeline (command → validate →
events → fold).
- Aggregates validate commands and emit events; state is a fold over the
append-only log; snapshots bound replay cost. Replay/audit are native.
- **Performance (cited/estimated):** in-process Rust event application is
memory-bandwidth-bound — order 10⁵10⁶ small events/s per core is the
commonly reported range for fold-style aggregates; dedicated stores
(EventStoreDB) sustain tens of thousands of appends/s over the network.
No game semantics: phases, visibility, simultaneity all DIY.
### 5. bevy_ecs 0.x (Rust) — cited
Archetypal ECS; the world/spatial layer in our architecture, surveyed as a
kernel candidate for completeness.
- Cache-friendly iteration: millions of entity-component accesses per frame
(cited from Bevy's own benches; ns-scale per component access).
- No authoritative command/event pipeline, no replay, no hidden-info
projection; determinism requires care (system ordering, hash maps).
Confirms the ADR-anticipated split: ECS for world representation,
**typed aggregates for the semantic kernel** — not a competitor on this
capability.
---
## Baselines (benchmark-to-beat)
| Dimension | Baseline holder | Metric | Value | Provenance |
|---|---|---|---|---|
| D1 ease of specification | boardgame.io | LOC to express the synthetic 3p commit/reveal game (declarative object) | ~45 LOC | measured (harness bench.js game def) |
| D1 | — (no candidate) | rule-to-scenario traceability (M-D1-COV) | 0 % — none of the candidates link rules to tests | measured/observed |
| D2 implementation weight | boardgame.io | transitive deps / install size | 120 pkgs / 37 MB | measured |
| D3 throughput | boardgame.io | applied moves/s, 3p workload @5k moves | 1,930 moves/s | measured, bnt-lap001 |
| D3 scaling | boardgame.io | throughput @20k vs @5k moves | 0.45× (superlinear cost) | measured, bnt-lap001 |
| D3 memory | boardgame.io | RSS @5k moves | 224 MB | measured, bnt-lap001 |
| D3 ceiling (adjacent layer) | in-proc event-sourcing (Rust) | events applied/s per core | ~10⁵10⁶ | cited/estimated — directional, caps our verdict at parity unless we measure a Rust comparator |
| D4 optionality | Rune | determinism enforced by tooling | static nondeterminism checks | cited |
| D4 | boardgame.io | replaceability of subsystems | plugin API, but JS-ecosystem-locked; no null/reference impl pattern | observed |
**Headline benchmark-to-beat for the Clay-Borg kernel (proposed for the
ADR):** ≥ 100,000 applied events/s sustained with **flat scaling** (throughput
@100k events within 10% of @5k), deterministic replay bit-identical, on the
same machine and workload shape as the boardgame.io harness.
## Verdict
- **Per dimension:** D1 — boardgame.io's declarative game object is the bar
to match; nobody has rule-to-scenario traceability (open surpass lane).
D2 — boardgame.io's 120-dep footprint is beatable by an order of
magnitude in Rust. D3 — boardgame.io is slow *and* degrades; the honest
comparison class is in-proc event sourcing (10⁵10⁶/s), and our D3
advantage over boardgame.io is partly language choice — the meaningful
target is **flat scaling + the 100k/s floor**, not the ×50 headline.
D4 — Rune's tooling-enforced determinism is the discipline to assimilate;
no candidate offers a null/reference/optimized port pattern.
- **What none of them do:** combine deterministic replayable authoritative
state, first-class simultaneous commit/reveal with hidden-information
projection, flat per-event cost with snapshots, and an embeddable
language-portable boundary. That combination is the surpass opportunity.
- **Risks in these baselines:** the boardgame.io harness measures the
headless *client* pipeline (includes subscription/log overhead — canonical
usage, but a bare server-side master could differ); the event-sourcing
numbers are cited, not locally measured; TTS and Rune numbers are
qualitative. The D3 event-sourcing row is directional and caps related
evidence verdicts at parity per MetricsAndScenarios §3.