Event System Reference
Detailed reference for event-system mechanics, envelope fields, validation, and troubleshooting.
For onboarding architecture, start with Event-driven system.
Command envelope fields
Command envelope type: internal/services/game/domain/command/registry.go.
Key fields:
campaign_id: required command scope.type: required command type (campaign.create,participant.update, etc.).actor_typeandactor_id: initiating principal.session_id: optional session scope.request_idandinvocation_id: request tracing through transport boundaries.entity_typeandentity_id: target hints for deciders/folders.system_idandsystem_version: required for system-owned commands.correlation_idandcausation_id: optional causal lineage.payload_json: canonicalized payload.
Event envelope fields
Event envelope type: internal/services/game/domain/event/registry.go.
Key fields:
campaign_id: required scope.type: event type string (participant.created,sys.daggerheart.*, etc.).timestamp: occurrence time.actor_typeandactor_id: origin principal.session_id,request_id,invocation_id: traceability.entity_type,entity_id: affected entity.system_id,system_version: required for system-owned events.correlation_id,causation_id: lineage.payload_json: immutable decision payload.- integrity fields (
seq, hash/signature metadata): append-time ownership.
Event intent details
event.Definition.Intent controls fold/projection behavior:
IntentProjectionAndReplay: folded + projected.IntentReplayOnly: folded only.IntentAuditOnly: journal-only.
Default intent is IntentProjectionAndReplay when omitted.
Decision model
A decision is produced by deciders and consumed by engine write orchestration.
- accepted decisions emit one or more events
- rejected decisions emit no domain mutation event
- mutating command paths should reject empty event decisions unless explicitly audit-only by contract
Registration surfaces
Runtime registration should remain coherent across these surfaces:
- command registry (
domain/command) - event registry (
domain/event) - module registry (
domain/module) - adapter registry (
domain/systems/adapter_registry.go) - metadata registry (
domain/systems/registry_bridge.go)
For system modules, manifest-driven registration in internal/services/game/domain/systems/manifest/manifest.go is the source of truth for module + metadata + adapter alignment.
Validation rules and why they matter
Fold coverage validation
Replay-relevant events must have fold handlers. Prevents runtime replay holes.
Adapter coverage validation
Projection-relevant events must have adapter handlers. Prevents silent projection staleness.
Audit-only dead handler guard
Audit-only events should not keep fold handlers. Prevents dead/unused fold code.
Namespace and ownership validation
- core paths must not emit system-owned events
- system paths must stay in
sys.<system_id>.*namespaces - system envelopes must carry system identity/version
Event naming conventions
- Core commands/events use domain nouns (
campaign.*,participant.*, etc.). - System-owned types use
sys.<system_id>.*naming. - Event types should be past-tense facts.
- Command types should be imperative actions.
Trigger semantics
When modeling behavior:
- command trigger captures intent
- decider evaluates invariant checks against state
- accepted decision emits immutable fact events
- projection layers consume events based on intent
Trigger evaluation must remain deterministic under replay.
Projections and consistency reference
- projections are derived and rebuildable
- replay correctness is more important than immediate denormalized convenience
- adapters must be idempotent under repeated event application
For replay and repair operations, use Replay operations.
Startup validator troubleshooting
Missing fold coverage
Symptom: startup/replay failure for a projection/replay event type.
Fix: register a fold handler for every replay-relevant event.
Missing adapter coverage
Symptom: event appends but projection does not update.
Fix: register adapter handler for every projection-relevant event.
Intent mismatch
Symptom: replay-only event expected to project, or audit-only event unexpectedly folded.
Fix: align event.Definition.Intent with intended behavior and handler coverage.
Namespace mismatch
Symptom: core emits sys.* or system emits core event names.
Fix: keep ownership boundaries explicit in decider output paths.