Module interface reference
This page documents the three registerable interface contracts that a game system must (or may) satisfy. All live in the game service domain layer.
module.Module
Package: domain/module/registry.go
Every game system registers exactly one Module with the module registry.
| Method | Return | Purpose |
|---|---|---|
ID() | string | Stable system identifier (e.g. "daggerheart"). |
Version() | string | Ruleset version string (e.g. "1.0.0"). |
RegisterCommands(*command.Registry) | error | Registers system-owned command definitions at startup. |
RegisterEvents(*event.Registry) | error | Registers system-owned event definitions at startup. |
EmittableEventTypes() | []event.Type | Declares all event types the decider can emit; validated against the event registry at startup. |
Decider() | Decider | Returns the system command handler (see below). |
Folder() | Folder | Returns the system state folder (see below). |
StateFactory() | StateFactory | Returns the factory that seeds initial system state for snapshots and characters. |
module.Decider
type Decider interface {
Decide(state any, cmd command.Command, now func() time.Time) command.Decision
}
Pure function: inspects current state and command, returns accepted events or rejections. Never mutates state.
module.Folder (alias for fold.Folder)
type Folder interface {
Fold(state any, evt event.Event) (any, error)
FoldHandledTypes() []event.Type
}
Applies a single event to state, returning the updated state. FoldHandledTypes enables startup coverage validation.
module.StateFactory
| Method | Purpose |
|---|---|
NewSnapshotState(campaignID) | Seeds campaign-level system state on first system event. |
NewCharacterState(campaignID, characterID, kind) | Seeds character-level system state on profile creation. |
Both return any. Implementations must be deterministic for replay safety.
systems.GameSystem
Package: domain/systems/registry_bridge.go
Registered in the MetadataRegistry for API-layer dispatch and system metadata.
| Method | Return | Purpose |
|---|---|---|
ID() | SystemID | Domain-layer system identifier. |
Version() | string | Ruleset version. |
Name() | string | Human-readable display name. |
RegistryMetadata() | RegistryMetadata | Implementation stage, operational status, access level. |
StateHandlerFactory() | StateHandlerFactory | Typed state handlers for the API bridge (resource/damage abstractions). May be nil. |
OutcomeApplier() | OutcomeApplier | Applies roll outcomes to game state. May be nil. |
systems.Adapter
Package: domain/systems/adapter_registry.go
Registered in the AdapterRegistry for projection-side event handling.
| Method | Return | Purpose |
|---|---|---|
ID() | string | System identifier. |
Version() | string | System version. |
Apply(ctx, event.Event) | error | Projects a system event into the system-specific projection store. |
Snapshot(ctx, campaignID) | (any, error) | Returns the current projected state for a campaign. |
HandledTypes() | []event.Type | Declares handled event types for startup validation against emittable types. |
Optional module interfaces
A Module may additionally implement these interfaces. The engine probes via type assertion at resolution time.
| Interface | Method | When called |
|---|---|---|
CharacterReadinessProvider | BindCharacterReadiness(campaignID, stateMap) | Session-start readiness evaluation. Returns a bound CharacterReadinessEvaluator. |
SessionStartBootstrapProvider | BindSessionStartBootstrap(campaignID, stateMap) | First-session bootstrap. Returns a bound SessionStartBootstrapEmitter. |
CommandTyper | DeciderHandledCommands() | Startup validation verifies decider covers all registered system commands. |
Typed escape hatches for any-typed state
Because Module passes state as any, system authors use generic helpers to recover type safety without hand-written assertions:
TypedDecider[S]– wraps a typed decide function; assertsanytoSbefore calling the inner function.TypedFolder[S]– wraps a typed fold function with the same pattern.FoldRouter[S]– dispatches fold events to per-type handler functions with automatic JSON payload unmarshaling viaHandleFold[S, P].
All three live in domain/module/. See domain/module/typed.go and domain/module/fold_router.go for signatures.