@eigeninteractive/testkit
@eigeninteractive/testkit — drive a game's rules through the real kernel without a
Worker, a database or a network. Build a table, submit actions as seats,
assert on the resulting transitions and per-seat observations.
Interfaces
ActionCase
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:82
A game-action case — exercises schemas, applyAction, and (through
expected.observation) computeObservation for the acting seat.
Properties
action
action: JsonObject;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:93
config
config: JsonObject;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:85
expected
expected: {
observation?: JsonObject;
outcome?: OutcomeEntry[] | null;
pending?: number[];
state?: JsonObject;
valid: boolean;
};
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:94
observation?
optional observation?: JsonObject;
outcome?
optional outcome?: OutcomeEntry[] | null;
pending?
optional pending?: number[];
state?
optional state?: JsonObject;
valid
valid: boolean;
kind
kind: "action";
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:83
name
name: string;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:84
obs?
optional obs?: JsonObject;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:88
Dart-side observation payload; unused here (defaults to state).
participantCount?
optional participantCount?: number;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:91
pending
pending: number[];
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:89
playerIndex
playerIndex: number;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:90
rngSeed?
optional rngSeed?: string;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:92
state
state: JsonObject;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:86
BotSeatableCase
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:118
A botSeatable predicate case.
Properties
botConfig
botConfig: JsonObject;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:122
expected
expected: boolean;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:123
gameConfig
gameConfig: JsonObject;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:121
kind
kind: "botSeatable";
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:119
name
name: string;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:120
BuildGameContractOptions
Defined in: eigen-server/packages/testkit/src/game-contract.ts:45
Inputs for building a GameContract without writing it.
Extended by
Properties
fixturesRoot?
optional fixturesRoot?: any;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:51
Root containing v<N>/*.json twin fixtures.
game
game: string;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:47
Stable display name used as the generated Dart type prefix.
gameModule
gameModule: GameModule;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:49
Authoritative TypeScript rules registry.
CommitInput
Defined in: eigen-server/packages/kernel/dist/index.d.ts:285
Properties
game
game: GameRow;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:286
intent
intent: Intent;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:291
now
now: number;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:294
The commit instant (epoch ms) — sampled once by the host, never read here.
roster
roster: Seat[];
Defined in: eigen-server/packages/kernel/dist/index.d.ts:290
rules
rules: GameRules;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:297
The version unit for the game's schemaVersion, already resolved by
the host from the GameModule.versions map.
staleViews?
optional staleViews?: {
current: SeatView | null;
expected: SeatView | null;
};
Defined in: eigen-server/packages/kernel/dist/index.d.ts:305
Same-view material for a stale game action: the acting seat's stored
frames at expectedVersion and at the current version. Only consulted
when intent.expectedVersion < state.version; if absent (or either
frame is missing — e.g. compacted away), the stale action is rejected
conservatively.
current
current: SeatView | null;
expected
expected: SeatView | null;
state
state: StateRow | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:289
The latest transition, or null before v0 (only a start intent is
meaningful then).
CommitPlan
Defined in: eigen-server/packages/kernel/dist/index.d.ts:351
Properties
action
action: TransitionAction | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:354
alarm
alarm: number | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:367
The instant the DO must arm its alarm at — the true deadline plus the grace window — or null to clear it.
effects
effects: Effect[];
Defined in: eigen-server/packages/kernel/dist/index.d.ts:368
frames
frames: ObservationFrame[];
Defined in: eigen-server/packages/kernel/dist/index.d.ts:357
Per-seat projected frames (identified seats only) — persisted with the transition, fanned out over sockets. No raw state escapes the kernel.
nextState
nextState: StateRow;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:353
The next transition row, already versioned (v+1, or 0 for start).
outcomes
outcomes: OutcomeEntry[] | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:364
Per-seat results when this transition ends the game, else null.
Rating deltas are deliberately NOT here: they depend on global cross-game
priors (D1-domain data the kernel must never need). The D1 applier
computes them inside the rating CAS via computeRatings (ratings.ts) and
the host delivers them as a follow-up versioned ratings transition.
EmitGameContractOptions
Defined in: eigen-server/packages/testkit/src/game-contract.ts:55
Inputs for emitting or checking a GameContract file.
Extends
Properties
fixturesRoot?
optional fixturesRoot?: any;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:51
Root containing v<N>/*.json twin fixtures.
Inherited from
BuildGameContractOptions.fixturesRoot
game
game: string;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:47
Stable display name used as the generated Dart type prefix.
Inherited from
gameModule
gameModule: GameModule;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:49
Authoritative TypeScript rules registry.
Inherited from
BuildGameContractOptions.gameModule
output
output: any;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:57
Destination game-contract.json path.
GameContract
Defined in: eigen-server/packages/testkit/src/game-contract.ts:37
Language-neutral schemas and fixtures shared by a game's Worker and app.
Properties
fixtures
fixtures: GameContractFixture[];
Defined in: eigen-server/packages/testkit/src/game-contract.ts:41
formatVersion
formatVersion: 1;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:38
game
game: string;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:39
versions
versions: Record<string, GameContractVersion>;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:40
GameContractFixture
Defined in: eigen-server/packages/testkit/src/game-contract.ts:19
One validated twin-fixture document embedded in a GameContract.
Properties
document
document: unknown;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:23
Validated fixture document, retained in its original JSON shape.
path
path: string;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:21
POSIX-style path relative to the supplied fixtures root.
GameContractVersion
Defined in: eigen-server/packages/testkit/src/game-contract.ts:27
The four JSON Schemas emitted for one game schemaVersion.
Properties
schemas
schemas: {
action: Record<string, unknown>;
config: Record<string, unknown>;
observation: Record<string, unknown>;
state: Record<string, unknown>;
};
Defined in: eigen-server/packages/testkit/src/game-contract.ts:28
action
action: Record<string, unknown>;
config
config: Record<string, unknown>;
observation
observation: Record<string, unknown>;
state
state: Record<string, unknown>;
GameRow
Defined in: eigen-server/packages/kernel/dist/index.d.ts:223
The game's standing configuration — the DO meta snapshot.
Properties
budgetSeconds
budgetSeconds: number | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:230
config
config: JsonObject;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:228
Stored creation config; parsed against the version unit's config schema before any hook sees it.
incrementSeconds
incrementSeconds: number | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:231
rated
rated: boolean;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:232
ratingPool
ratingPool: string | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:233
schemaVersion
schemaVersion: number;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:225
status
status: GameStatus;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:224
turnSeconds
turnSeconds: number | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:229
ObservationFrame
Defined in: eigen-server/packages/kernel/dist/index.d.ts:115
One seat's projected frame, tagged with its seat. The host stamps version/timing when it persists and fans these out.
Properties
data
data: JsonObject;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:117
pendingPlayers
pendingPlayers: number[];
Defined in: eigen-server/packages/kernel/dist/index.d.ts:118
playerIndex
playerIndex: number;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:116
RatingPoolCase
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:104
A ratingPool predicate case. Omitted timing fields mean null.
Properties
access
access: GameAccess;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:107
budgetSeconds?
optional budgetSeconds?: number | null;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:109
config
config: JsonObject;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:113
expected
expected: string | null;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:114
incrementSeconds?
optional incrementSeconds?: number | null;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:110
kind
kind: "ratingPool";
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:105
maxPlayers
maxPlayers: number;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:112
minPlayers
minPlayers: number;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:111
name
name: string;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:106
turnSeconds?
optional turnSeconds?: number | null;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:108
Rejected
Defined in: eigen-server/packages/kernel/dist/index.d.ts:45
An intent the kernel refused. A value, not a throw — rejections are part of the normal protocol.
Properties
code
code: RejectCode;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:47
message
message: string;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:48
rejected
rejected: true;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:46
Seat
Defined in: eigen-server/packages/kernel/dist/index.d.ts:237
One seat of the roster. Both ids null ⇒ the account was purged mid-game (the seat plays on as "Deleted User" for display, but can never act).
Properties
botId
botId: string | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:240
playerIndex
playerIndex: number;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:238
type
type: "bot" | "human";
Defined in: eigen-server/packages/kernel/dist/index.d.ts:241
userId
userId: string | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:239
SeatView
Defined in: eigen-server/packages/kernel/dist/index.d.ts:93
A seat's stored projection at one version — what the same-view compare
runs on (and what the DO persists per transition as frames[]).
Properties
data
data: JsonObject;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:94
pendingPlayers
pendingPlayers: number[];
Defined in: eigen-server/packages/kernel/dist/index.d.ts:95
StateRow
Defined in: eigen-server/packages/kernel/dist/index.d.ts:245
The latest committed transition — state plus the engine-owned clocks. All instants are epoch milliseconds.
Properties
deadline
deadline: number | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:252
The true turn deadline shown to clients; the alarm arms at
deadline + grace.
pending
pending: number[];
Defined in: eigen-server/packages/kernel/dist/index.d.ts:248
playerTimes
playerTimes: number[] | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:254
Per-seat budget banks (ms), budget mode only.
rngSeed
rngSeed: string;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:249
state
state: JsonObject;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:247
turnStartedAt
turnStartedAt: number | null;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:255
version
version: number;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:246
TwinFixtureFile
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:75
One fixture file: cases targeting one schemaVersion unit.
Properties
cases
cases: TwinFixtureCase[];
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:77
schemaVersion
schemaVersion: number;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:76
Type Aliases
Effect
type Effect =
| {
botId: string;
kind: "wakeBot";
seat: number;
}
| {
kind: "notifyTurn";
seat: number;
userId: string;
}
| {
kind: "notifyFinished";
userIds: string[];
};
Defined in: eigen-server/packages/kernel/dist/index.d.ts:339
A push/wake the host should attempt post-commit (single attempt + error log — no retry machinery in v1). The kernel names seats; the host resolves delivery (FCM targets, bot webhook vs local bot).
Intent
type Intent =
| {
kind: "start";
seed: string;
}
| {
actor: "user" | "bot";
data: unknown;
expectedVersion: number;
kind: "action";
seat: number;
}
| {
kind: "lifecycle";
type: "timeout";
}
| {
kind: "lifecycle";
seat: number;
type: "forfeit" | "autoForfeit";
};
Defined in: eigen-server/packages/kernel/dist/index.d.ts:259
What the host asks the kernel to do — the kernel-facing half of a
Command (authorization already happened at the edge; dedupe at the DO).
Union Members
Type Literal
{
kind: "start";
seed: string;
}
kind
kind: "start";
seed
seed: string;
The game's base RNG seed, freshly generated by the host
(randomSeed()); stored on v0 and copied to every later row.
Type Literal
{
actor: "user" | "bot";
data: unknown;
expectedVersion: number;
kind: "action";
seat: number;
}
actor
actor: "user" | "bot";
data
data: unknown;
The raw move payload — parsed against the unit's action schema.
expectedVersion
expectedVersion: number;
The version the client computed the move against. Equal to the current version in the common case; a lower value is arbitrated by the same-view rule.
kind
kind: "action";
seat
seat: number;
Type Literal
{
kind: "lifecycle";
type: "timeout";
}
Type Literal
{
kind: "lifecycle";
seat: number;
type: "forfeit" | "autoForfeit";
}
forfeit = a voluntary resign (a user action); autoForfeit = the
engine-driven variant (account purge; identity-less system action).
RejectCode
type RejectCode =
| "notActive"
| "notReady"
| "expired"
| "notPending"
| "stateUpdated"
| "invalidPayload"
| "illegalMove"
| "abstain";
Defined in: eigen-server/packages/kernel/dist/index.d.ts:24
Why an intent was refused. Stable machine codes — the host's transport mapping and the client's retry policy key on these, so treat renames as breaking.
TwinFixtureCase
type TwinFixtureCase =
| ActionCase
| RatingPoolCase
| BotSeatableCase;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:126
Variables
GAME_CONTRACT_FORMAT_VERSION
const GAME_CONTRACT_FORMAT_VERSION: 1 = 1;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:16
Current format of the language-neutral contract consumed by EigenInteractive's Dart generator.
Functions
buildGameContract()
function buildGameContract(options): GameContract;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:121
Build a deterministic in-memory contract without touching the filesystem.
Parameters
| Parameter | Type |
|---|---|
options | BuildGameContractOptions |
Returns
checkConfiguredGameContract()
function checkConfiguredGameContract(root?): Promise<void>;
Defined in: eigen-server/packages/testkit/src/contract-command.ts:76
Fails when the conventionally configured contract is absent or stale.
Use this in CI through eigen-contract --check.
Parameters
| Parameter | Type |
|---|---|
root | any |
Returns
Promise<void>
checkGameContract()
function checkGameContract(options): void;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:165
Fail when an emitted contract is missing or differs from its inputs.
Parameters
| Parameter | Type |
|---|---|
options | EmitGameContractOptions |
Returns
void
commit()
function commit(input): CommitPlan | Rejected;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:372
Parameters
| Parameter | Type |
|---|---|
input | CommitInput |
Returns
deepEquals()
function deepEquals(a, b): boolean;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:480
Structural JSON equality. Object keys with undefined values count as
absent (matching how schema libraries model optional fields); array order
matters.
Parameters
| Parameter | Type |
|---|---|
a | Json | undefined |
b | Json | undefined |
Returns
boolean
deriveRng()
function deriveRng(seed, version): Rng;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:388
The deterministic RNG for one transition: rand-seed's sfc32 keyed by the
game's base seed and the state version the envelope will commit as. The
same (seed, version) always yields the same draw sequence — a replay
re-derives it — and every transition gets an independent stream, so hooks
draw as many values as they need with no cross-invocation state. The
derivation is fixed, so recorded games stay replayable.
Parameters
| Parameter | Type |
|---|---|
seed | string |
version | number |
Returns
Rng
emitConfiguredGameContract()
function emitConfiguredGameContract(root?): Promise<void>;
Defined in: eigen-server/packages/testkit/src/contract-command.ts:67
Emits game-contract.json from an EigenInteractive package's conventional layout.
This is the programmatic form of the eigen-contract executable. Most
games should invoke the executable through their package script.
Parameters
| Parameter | Type |
|---|---|
root | any |
Returns
Promise<void>
emitGameContract()
function emitGameContract(options): void;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:159
Emit one deterministic, newline-terminated game-contract.json.
Parameters
| Parameter | Type |
|---|---|
options | EmitGameContractOptions |
Returns
void
evaluateTwinCase()
function evaluateTwinCase(rules, kase): string[];
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:274
Run one fixture case against a rules unit, returning failure descriptions (empty ⇒ the case passes). Pure — the file-reading test registrar is twinFixtureTests.
Parameters
| Parameter | Type |
|---|---|
rules | GameRules |
kase | TwinFixtureCase |
Returns
string[]
gameContractFilename()
function gameContractFilename(game): string;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:173
A useful default filename for scripts that accept an output directory.
Parameters
| Parameter | Type |
|---|---|
game | string |
Returns
string
gameContractJson()
function gameContractJson(options): string;
Defined in: eigen-server/packages/testkit/src/game-contract.ts:154
Render one deterministic, newline-terminated contract document.
Parameters
| Parameter | Type |
|---|---|
options | BuildGameContractOptions |
Returns
string
isRejected()
function isRejected(result): result is Rejected;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:371
Type guard: did commit() refuse the intent?
Parameters
| Parameter | Type |
|---|---|
result | CommitPlan | Rejected |
Returns
result is Rejected
parseTwinFixtureFile()
function parseTwinFixtureFile(path, json): TwinFixtureFile;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:247
Validate one fixture file's parsed JSON, or throw naming the offending file, case, and field. Exported so a repo can lint its fixtures without running them.
Parameters
| Parameter | Type |
|---|---|
path | string |
json | unknown |
Returns
projectView()
function projectView(rules, args): SeatView;
Defined in: eigen-server/packages/testkit/src/kernel-scenarios.ts:39
Project one seat's view of a state — the stored-frame shape the same-view
rule compares (commit()'s staleViews input). Convenience for scenario
tests that replay a simultaneous-move race.
Parameters
| Parameter | Type | Description |
|---|---|---|
rules | GameRules | - |
args | { cause?: TransitionCause; config: JsonObject; isReplay?: boolean; participantCount?: number; pending: number[]; seat: number | null; state: JsonObject; } | - |
args.cause? | TransitionCause | - |
args.config | JsonObject | - |
args.isReplay? | boolean | - |
args.participantCount? | number | - |
args.pending | number[] | - |
args.seat | number | null | The seat to project for, or null for a viewer. |
args.state | JsonObject | - |
Returns
randomSeed()
function randomSeed(): string;
Defined in: eigen-server/packages/kernel/dist/index.d.ts:381
A fresh base seed for a new game: 128 random bits, hex-encoded. Stored on the game's v0 state row and copied onto every later row (server-only — never expose it: the whole randomness of the game is derivable from it).
Returns
string
twinFixtureTests()
function twinFixtureTests(gameModule, fixturesRoot): void;
Defined in: eigen-server/packages/testkit/src/twin-fixtures.ts:290
Register one vitest test per fixture case found under fixturesRoot
(layout: <root>/v<N>/*.json). Call at the top level of a test module
running in a Node environment.
Parameters
| Parameter | Type |
|---|---|
gameModule | GameModule |
fixturesRoot | any |
Returns
void
References
DEADLINE_GRACE_MS
Re-exports DEADLINE_GRACE_MS