Skip to main content

@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

BuildGameContractOptions.game

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

ParameterType
optionsBuildGameContractOptions

Returns

GameContract


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

ParameterType
rootany

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

ParameterType
optionsEmitGameContractOptions

Returns

void


commit()

function commit(input): CommitPlan | Rejected;

Defined in: eigen-server/packages/kernel/dist/index.d.ts:372

Parameters

ParameterType
inputCommitInput

Returns

CommitPlan | Rejected


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

ParameterType
aJson | undefined
bJson | 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

ParameterType
seedstring
versionnumber

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

ParameterType
rootany

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

ParameterType
optionsEmitGameContractOptions

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

ParameterType
rulesGameRules
kaseTwinFixtureCase

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

ParameterType
gamestring

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

ParameterType
optionsBuildGameContractOptions

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

ParameterType
resultCommitPlan | 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

ParameterType
pathstring
jsonunknown

Returns

TwinFixtureFile


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

ParameterTypeDescription
rulesGameRules-
args{ cause?: TransitionCause; config: JsonObject; isReplay?: boolean; participantCount?: number; pending: number[]; seat: number | null; state: JsonObject; }-
args.cause?TransitionCause-
args.configJsonObject-
args.isReplay?boolean-
args.participantCount?number-
args.pendingnumber[]-
args.seatnumber | nullThe seat to project for, or null for a viewer.
args.stateJsonObject-

Returns

SeatView


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

ParameterType
gameModuleGameModule
fixturesRootany

Returns

void

References

DEADLINE_GRACE_MS

Re-exports DEADLINE_GRACE_MS