asyncapi: 3.1.0 info: title: Galaxy Game Master Runtime Events Contract version: 1.0.0 description: | Stable Redis Streams contract for runtime snapshot updates and game finish events published by `Game Master` toward `Game Lobby` on the `gm:lobby_events` stream. Two distinct message types share the channel and are discriminated by the `event_type` field on the payload: - `RuntimeSnapshotUpdate` (`event_type=runtime_snapshot_update`) is published whenever a turn was generated (success or failure), the runtime status transitioned, or the engine health summary changed in response to a `runtime:health_events` observation. Duplicates are suppressed when the summary did not change. - `GameFinished` (`event_type=game_finished`) is published once when the engine reports `finished:true` on a turn-generation response. The runtime stays in `status=finished` indefinitely; no further events are published for the game. Both payload schemas are closed (`additionalProperties: false`). Adding a field to either payload after this contract was frozen is a breaking change that requires a contract bump and a coordinated consumer update. Polymorphism: the AsyncAPI surface uses two messages on one channel and one `send` operation per message. The `runtime_health-asyncapi.yaml` style of a single message with `oneOf` details is not used here because the two payload shapes have no shared field set beyond the discriminator and the `game_id`. See `gamemaster/docs/stage06-contract-files.md`. channels: lobbyEvents: address: gm:lobby_events messages: runtimeSnapshotUpdate: $ref: '#/components/messages/RuntimeSnapshotUpdate' gameFinished: $ref: '#/components/messages/GameFinished' operations: publishRuntimeSnapshotUpdate: action: send summary: Publish a runtime snapshot update for Game Lobby. channel: $ref: '#/channels/lobbyEvents' messages: - $ref: '#/channels/lobbyEvents/messages/runtimeSnapshotUpdate' publishGameFinished: action: send summary: Publish a game finish event for Game Lobby. channel: $ref: '#/channels/lobbyEvents' messages: - $ref: '#/channels/lobbyEvents/messages/gameFinished' components: messages: RuntimeSnapshotUpdate: name: RuntimeSnapshotUpdate title: Runtime snapshot update summary: Snapshot of one game's runtime state, published on transitions and health changes. payload: $ref: '#/components/schemas/RuntimeSnapshotUpdatePayload' examples: - name: runningTurnReady summary: Snapshot published after a successful turn generation. payload: event_type: runtime_snapshot_update game_id: game-123 current_turn: 17 runtime_status: running engine_health_summary: healthy player_turn_stats: - user_id: user-1 planets: 4 population: 12000 - user_id: user-2 planets: 3 population: 9000 occurred_at_ms: 1775121700000 GameFinished: name: GameFinished title: Game finished summary: Terminal event published once when the engine reports finished:true on a turn-generation response. payload: $ref: '#/components/schemas/GameFinishedPayload' examples: - name: gameFinished summary: Game finished on turn 42; final per-player stats included. payload: event_type: game_finished game_id: game-123 final_turn_number: 42 runtime_status: finished player_turn_stats: - user_id: user-1 planets: 6 population: 25000 - user_id: user-2 planets: 0 population: 0 finished_at_ms: 1775130000000 schemas: RuntimeStatus: type: string enum: - starting - running - generation_in_progress - generation_failed - stopped - engine_unreachable - finished description: Runtime status enum; identical to the value used in the internal REST contract. PlayerTurnStat: type: object additionalProperties: false required: - user_id - planets - population properties: user_id: type: string description: Platform user identifier of the player. planets: type: integer minimum: 0 description: Number of planets controlled by the player at the snapshot turn. population: type: integer minimum: 0 description: Total population controlled by the player at the snapshot turn. RuntimeSnapshotUpdatePayload: type: object additionalProperties: false required: - event_type - game_id - current_turn - runtime_status - engine_health_summary - player_turn_stats - occurred_at_ms properties: event_type: type: string const: runtime_snapshot_update description: Discriminator pinned to `runtime_snapshot_update`; consumers dispatch on this value. game_id: type: string description: Opaque stable game identifier. current_turn: type: integer minimum: 0 description: Last completed turn number; zero when the snapshot reflects the pre-first-turn state. runtime_status: $ref: '#/components/schemas/RuntimeStatus' engine_health_summary: type: string description: Short text summary of engine health; empty until the first health observation. player_turn_stats: type: array items: $ref: '#/components/schemas/PlayerTurnStat' description: Per-player stats projection; empty before any turn has generated. occurred_at_ms: type: integer format: int64 description: UTC Unix milliseconds when Game Master observed the underlying transition. GameFinishedPayload: type: object additionalProperties: false required: - event_type - game_id - final_turn_number - runtime_status - player_turn_stats - finished_at_ms properties: event_type: type: string const: game_finished description: Discriminator pinned to `game_finished`; consumers dispatch on this value. game_id: type: string description: Opaque stable game identifier. final_turn_number: type: integer minimum: 0 description: Last turn number generated before the engine reported finished:true. runtime_status: $ref: '#/components/schemas/RuntimeStatus' player_turn_stats: type: array items: $ref: '#/components/schemas/PlayerTurnStat' description: Final per-player stats projection at the finish turn. finished_at_ms: type: integer format: int64 description: UTC Unix milliseconds when Game Master persisted the finish transition.