11 KiB
CB-RES-0001: game-state kernel
capability: game.kernel.authoritative-state status: approved # adversarial review 2026-07-31: challenge + response in history/ tier: L (structural L, chaos d10=9 → no override) runnable-baseline: invoked — harness in research/CB-RES-0001-harness/boardgame-io/ review-trail: history/260731-game-kernel-{research,challenge,response}.md
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; revised same day after adversarial review.
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) + frameworkctx(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) and, unless
disableUndois set, an undo stack holding a full state snapshot per move. -
Determinism/replay: seeded RNG via
randomplugin; log + seed give replay and time travel. Measured: same seed → identical state hash across runs; different seed diverges. ✅ -
Hidden information:
playerViewprojection (e.g.STRIP_SECRET) — server strips secret state per player. Not exercised by our workload (provenance note: commit/reveal shape measured; hidden-info cost not). -
Simultaneous actions:
activePlayersstages give simultaneous move windows; no built-in cryptographic commit/reveal — commitment is plain state the server can see. -
Maturity: 12.4k GitHub stars, but inactive — last npm release 0.50.2 ≈ 4 years ago (checkable on npm; Snyk lists maintenance Inactive).
-
Measured performance (harness, synthetic 3-player GROUND-shaped commit/reveal workload, Node v24,
bnt-lap001; run-to-run variance on this machine is material — ±25% observed on identical configs):applied moves default (moves/s) disableUndo(moves/s)RSS after run (isolated) 5,000 1,439–1,930 1,118 ~100 MB 10,000 1,605 1,076 132 MB 20,000 870 942 153 MB 40,000 — 733 232 MB 100,000 DNF @300 s DNF @240 s — Two degradation mechanisms, separately attributed: (a) the undo stack — an O(n) per-move array spread with full state snapshots — is the dominant superlinear term at small N and is disable-able via the documented
disableUndoflag; (b) with undo disabled, throughput still falls 34% from 5k→40k and 100k still does not finish, consistent with unbounded client log/deltalog accumulation, which has no client-side off switch in 0.50.2. Even the best configuration degrades with history. (updatePlayerIDin the timed loop measured separately: ~2 µs/call, <0.5% contamination.) -
Weight: 120 transitive npm packages, 37 MB
node_modules, core package 3.9 MB (independently re-verified in review).
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).
- Pattern source for object-attached behavior and hand zones; architecturally the anti-model for an authoritative kernel.
3. Rune SDK (JS) — cited
Modern (active) deterministic multiplayer engine for casual web games.
- Data model/mutation: pure
logic.js— game state + action functions, statically checked for nondeterminism (mutation escape,Math.randompatched deterministic). - Sync: predict-rollback: all clients + server simulate the same deterministic logic. Strongest determinism discipline of the candidates — enforced by tooling, not convention.
- Limits: platform-bound (Rune's hosted ecosystem), not an embeddable open kernel; no phase framework, hidden-information projection, or event-sourced replay surface.
4. OpenSpiel (C++/Python, DeepMind) — cited (added after review)
Research games kernel explicitly built for simultaneous-move and imperfect-information games.
- Deterministic state; serializable; replay via action histories; information-state abstractions for imperfect information; large game library. Active. As an in-process C++ kernel it is also a credible D3 comparator (unmeasured here — open follow-up).
- Limits: research-oriented — no client visibility projection layer, no networking/session model, no snapshot format, monolithic C++/Python build rather than an embeddable capability boundary. The semantics overlap with our kernel is real; the production layer is absent.
5. Ludii / GGP-GDL lineage (JVM) — cited (added after review)
General game systems whose core value is ease of rule specification (the D1 dimension): games written as ludemes (Ludii, 1,000+ games) or GDL rules, executed by a general engine.
- Proof that rule description languages can cover enormous game spaces compactly; the D1 literature our kernel spec should be checked against.
- Limits: research/archival focus; no production multiplayer stack, no hidden-info projection for clients, JVM-bound; performance oriented to AI playouts, not authoritative session serving.
6. Event-sourcing kernels (Rust cqrs-es pattern / EventStoreDB) — cited
Aggregates validate commands and emit events; state is a fold over the append-only log; snapshots bound replay cost. Replay/audit native. Performance: estimated — order 10⁵–10⁶ small events/s per core for in-process fold-style application; dedicated stores sustain tens of thousands of appends/s over the network. No reproducible citation held; treated as directional only. No game semantics.
7. bevy_ecs (Rust) — cited
Archetypal ECS; the world/spatial layer in our architecture. Millions of entity-component accesses per frame (Bevy's published benches). No authoritative command/event pipeline, replay, or hidden-info projection — confirms the split: ECS for world representation, typed aggregates for the semantic kernel.
Secondary references (not fully surveyed)
- Board Game Arena Studio — dominant commercial turn-based rules framework (PHP): server-authoritative state machine, hidden info, full replay. Closed platform; stronger commercial reference than TTS.
- Colyseus — active JS authoritative-state multiplayer server; room state sync without game-rules semantics (no phases/legality/replay framework). The "active JS" counterweight to inactive boardgame.io.
- Vassal — module player for humans; no programmable rules kernel.
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) | ~36 LOC | measured (bench.js); gameable — secondary indicator |
| D1 (qualitative bar) | Ludii/GDL | rule-description-language coverage of large game spaces | qualitative | cited |
| D2 implementation weight | boardgame.io | transitive deps / install size | 120 pkgs / 37 MB | measured |
| D3 throughput | boardgame.io (disableUndo, best config) |
applied moves/s, 3p workload @5k moves | ~1,100 (default config 1,400–1,900; ±25% machine variance) | measured, bnt-lap001 |
| D3 scaling | boardgame.io (disableUndo, best config) |
throughput @40k vs @5k moves | 0.66× (default config: 0.45× @20k; both DNF @100k) | measured, bnt-lap001 |
| D3 memory | boardgame.io | RSS after run, isolated process | ~100 MB @5k → 232 MB @40k | indicative (raw RSS incl. Node baseline) |
| 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 |
Observation (not a baseline row): no surveyed candidate links numbered rules to test scenarios (M-D1-COV-style traceability); any nonzero coverage exceeds the field, so this is a direction, not a bar.
Headline target for the Clay-Borg kernel (stipulated engineering target, not competitor-derived): ≥ 100,000 applied events/s sustained with flat scaling (throughput @100k events within 10% of @5k), deterministic replay bit-identical, same machine and workload shape as the harness. The event-sourcing ceiling row is an estimate; until a Rust comparator is measured locally (open follow-up), evidence rows leaning on it cap at parity per MetricsAndScenarios §3.
Verdict
- D1: boardgame.io's declarative game object is the bar to match for compactness; Ludii/GDL is the literature bar for rule-language expressiveness. Rule-to-scenario traceability is an open lane no one occupies.
- D2: boardgame.io's 120-dep/37 MB footprint is beatable by an order of magnitude.
- D3: boardgame.io degrades with history even in its best measured configuration; our advantage over it is partly language choice, so the meaningful commitment is the stipulated flat-scaling + 100k/s target, not the multiplier over boardgame.io.
- D4: Rune's tooling-enforced determinism is the discipline to assimilate; no candidate offers a null/reference/optimized port pattern or a WIT-style embeddable boundary.
- The surpass opportunity, stated precisely: OpenSpiel covers simultaneous-move + imperfect-information semantics with deterministic replay; boardgame.io covers declarative rules + client projection + networking; Rune covers enforced determinism; event sourcing covers flat-cost replay with snapshots. No candidate combines the semantic coverage with a production projection/networking layer, snapshot-bounded flat-cost replay, and an embeddable, language-portable capability boundary. That combination — not raw speed over an inactive JS library — is what the Clay-Borg kernel should be built to demonstrate.
- Risks that remain: event-sourcing D3 row unsourced (estimate; parity-cap active); OpenSpiel unmeasured locally; harness measures the headless client pipeline (canonical usage — a bare server Master could differ); ±25% run-to-run variance on this machine; hidden-info cost unmeasured.