Adding a command, event, or game system
Canonical how-to for system-extension changes.
1. Add or change command/event definitions
- Update the owning registration surface:
- system modules:
RegisterCommandsandRegisterEventsininternal/services/game/domain/systems/<system>/module.go - core modules: registration in the owning
internal/services/game/domain/<area>/registry.go
- system modules:
- Update payload structs and validation in the same owning package.
- Add/update focused registration tests in that package.
2. Wire command behavior
- For core commands, add the route in the owning core package and keep
internal/services/game/app/domain.golimited to domain runtime composition. - Implement or extend decider logic in the owning module or aggregate package.
- Ensure emitted events are declared and validated by the registry.
- Add fold and adapter coverage for any replay- or projection-relevant events.
3. If adding a new game system
- Implement the system package in
internal/services/game/domain/systems/<system>/. - Add one
SystemDescriptorininternal/services/game/domain/systems/manifest/manifest.go. That descriptor is the built-in source of truth for:BuildModule→ write-path registrationBuildMetadataSystem→ API-facing system metadataBuildAdapter→ projection apply and replay repair
- Add module conformance tests using
internal/services/game/domain/module/testkit/. - If the system needs projection storage, add a system-owned store contract in the system package and keep store extraction owned by that system’s descriptor:
- keep the concrete backend implementation in the owning backend package
- expose any needed provider method on the concrete projection backend
- make
BuildAdapterextract the system store from the concrete store source it receives
- Add scenario coverage for the new system:
- place scenarios under
internal/test/game/scenarios/systems/<system_id>/ - add/select smoke entries in
internal/test/game/scenarios/manifests/ - use a system handle for mechanics (for example
local dh = scn:system(\"<SYSTEM_ID>\"))
- place scenarios under
- Update generated event docs after registration changes land.
4. If exposing AI orchestration tooling
- Add tool handlers in
internal/services/ai/orchestration/gametools/. - Register the tool in the appropriate
tools_catalog_*.godefinition file and add dispatch insession.go. - If the production tool surface changes, update
internal/services/ai/orchestration/gametools/tools.go, the relevanttools_catalog_*.gofile,internal/services/ai/orchestration/tool_policy.go, and the AI reference docs together. - Add/update tool-focused tests.
5. Startup validation debugging
If game service startup fails after registration changes, error messages are already scoped to the failing phase:
system module <id>@<version> <step>: <cause>points to module registration (register commands,register events, namespace, or emittable checks).registry validation <step>: <cause>points to post-registration coverage and consistency checks.system module registry mismatch: ...points to manifest-derived parity drift between module, metadata, and adapter registration.
Use these step labels first before deep code tracing.
6. Regenerate and verify
- targeted package tests for the owning core or system package
make smokemake checkmake game-architecture-checkmake event-catalog-checkmake docs-check
Canonical references
- Write-path model: Event-driven system
- System architecture: Game systems architecture
- System authoring details: Adding a game system
- Generated command/event contracts: Events index