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

201 lines
11 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: 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) + 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) and, unless `disableUndo` is set,
an **undo stack** holding a full state snapshot per move.
- **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. *Not exercised by our workload*
(provenance note: commit/reveal shape measured; hidden-info cost not).
- **Simultaneous actions:** `activePlayers` stages 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,4391,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 `disableUndo` flag; (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.
(`updatePlayerID` in 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.random`
patched 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,4001,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.