openapi: 3.0.3
info:
  title: Galaxy Game Service REST API
  version: v1
  description: |
    This specification documents the REST contract of `galaxy/game`.

    The service hosts a single game instance and exposes endpoints for game
    initialization, turn advancement, game-state queries, player reports, and
    batched player command execution.

    Transport rules:
    - request bodies are JSON
    - `PUT /api/v1/command` is rate-limited to one concurrent execution;
      requests that cannot acquire the execution slot within 100 ms receive
      `504 Gateway Timeout`
    - `501 Not Implemented` is returned without a body when the game has not
      been initialized
    - validation errors return `400` with `{"error": "message"}`
    - game-engine errors return `500` with `{"generic_error": "message", "code": integer}`
    - other internal errors return `500` with `{"error": "message"}`
servers:
  - url: http://localhost:8080
    description: Default local listener for Game Service.
tags:
  - name: GameLifecycle
    description: Game initialization, state retrieval, and turn advancement.
  - name: PlayerActions
    description: Player command execution, order validation, and turn-report retrieval.
  - name: Health
    description: Technical liveness probes used by Runtime Manager and operator tooling.
paths:
  /api/v1/admin/status:
    get:
      tags:
        - GameLifecycle
      operationId: adminGetGameStatus
      summary: Get the current game state
      description: |
        Returns the current game state including turn number, stage, and a
        summary of all players. Returns `501` if the game has not yet been
        initialized. Routed only from the trusted network segment that
        connects `Game Master` to the engine container.
      responses:
        "200":
          description: Current game state.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StateResponse"
        "501":
          description: Game has not been initialized yet.
        "500":
          $ref: "#/components/responses/InternalError"
  /api/v1/admin/init:
    post:
      tags:
        - GameLifecycle
      operationId: adminInitGame
      summary: Initialize a new game
      description: |
        Generates a new game instance with the supplied list of races.
        Requires at least 10 race entries. Routed only from the trusted
        network segment that connects `Game Master` to the engine
        container.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InitRequest"
      responses:
        "201":
          description: Game initialized successfully.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StateResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "500":
          $ref: "#/components/responses/InternalError"
  /api/v1/admin/race/banish:
    post:
      tags:
        - GameLifecycle
      operationId: adminBanishRace
      summary: Deactivate a race after a permanent platform-level removal
      description: |
        Deactivates the named race in the running engine. Called by `Game
        Master` after a Lobby-driven permanent membership removal. Routed
        only from the trusted network segment that connects `Game Master`
        to the engine container. 
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BanishRequest"
      responses:
        "204":
          description: Race deactivated; no response body.
        "400":
          $ref: "#/components/responses/ValidationError"
        "500":
          $ref: "#/components/responses/InternalError"
  /api/v1/report:
    get:
      tags:
        - PlayerActions
      operationId: getReport
      summary: Get a player turn report
      description: |
        Returns the full game report for the specified player and turn.
        `player` must be a non-blank race name. `turn` defaults to `0`.
      parameters:
        - $ref: "#/components/parameters/PlayerParam"
        - $ref: "#/components/parameters/TurnParam"
      responses:
        "200":
          description: Player turn report.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Report"
        "400":
          $ref: "#/components/responses/ValidationError"
        "500":
          $ref: "#/components/responses/InternalError"
  /api/v1/command:
    put:
      tags:
        - PlayerActions
      operationId: executeCommands
      summary: Execute a batch of player commands
      description: |
        Applies one or more game commands for the specified actor. Serialized
        to one concurrent execution; requests that cannot acquire the execution
        slot within 100 ms return `504 Gateway Timeout`. Returns `202 Accepted`
        with no body on success. Reserved for future use; player order
        submissions go through `/api/v1/order`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CommandRequest"
      responses:
        "202":
          description: All commands accepted.
        "400":
          $ref: "#/components/responses/ValidationError"
        "504":
          description: Command execution slot not acquired within 100 ms.
        "500":
          $ref: "#/components/responses/InternalError"
  /api/v1/order:
    put:
      tags:
        - PlayerActions
      operationId: validateOrder
      summary: Validate and store a player order without executing it
      description: |
        Validates and stores the game commands structurally without executing them.
        On success returns `202 Accepted` with the stored order, including the
        engine-assigned `updatedAt` timestamp used by clients to detect stale
        submissions.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CommandRequest"
      responses:
        "202":
          description: Order is structurally valid and stored.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserGamesOrder"
        "400":
          $ref: "#/components/responses/ValidationError"
        "500":
          $ref: "#/components/responses/InternalError"
    get:
      tags:
        - PlayerActions
      operationId: getOrder
      summary: Fetch the stored order for a player and turn
      description: |
        Returns the order previously stored by `PUT /api/v1/order` for the
        specified player and turn. Responds `204 No Content` when no order
        has been stored for that turn.
      parameters:
        - $ref: "#/components/parameters/PlayerParam"
        - $ref: "#/components/parameters/TurnParam"
      responses:
        "200":
          description: Stored player order for the requested turn.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserGamesOrder"
        "204":
          description: No order has been stored for this player on this turn.
        "400":
          $ref: "#/components/responses/ValidationError"
        "500":
          $ref: "#/components/responses/InternalError"
  /api/v1/battle/{turn}/{uuid}:
    get:
      tags:
        - PlayerActions
      operationId: getBattle
      summary: Fetch a single battle report
      description: |
        Returns the full `BattleReport` for the supplied `turn` and battle
        identifier. The `turn` segment must be a non-negative integer; the
        `uuid` segment must be a valid RFC 4122 UUID. Responds with
        `404 Not Found` when no battle is stored for the supplied pair.
      parameters:
        - $ref: "#/components/parameters/BattleTurnParam"
        - $ref: "#/components/parameters/BattleIDParam"
      responses:
        "200":
          description: Battle report for the supplied turn and identifier.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BattleReport"
        "400":
          $ref: "#/components/responses/ValidationError"
        "404":
          description: No battle exists for the supplied turn and identifier.
        "500":
          $ref: "#/components/responses/InternalError"
  /api/v1/admin/turn:
    put:
      tags:
        - GameLifecycle
      operationId: adminGenerateTurn
      summary: Advance the game to the next turn
      description: |
        Processes the current turn and generates the next one. Returns the
        updated game state. Routed only from the trusted network segment
        that connects `Game Master` to the engine container.
      responses:
        "200":
          description: Updated game state after turn generation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StateResponse"
        "500":
          $ref: "#/components/responses/InternalError"
  /healthz:
    get:
      tags:
        - Health
      operationId: healthz
      summary: Engine liveness probe
      description: |
        Returns `{"status":"ok"}` with HTTP `200` whenever the HTTP server
        is serving requests, regardless of whether the engine has been
        initialised through `POST /api/v1/admin/init`. Used by `Runtime
        Manager` to probe a freshly started container before `init` runs.
        Carries no game-state semantics; use `GET /api/v1/admin/status`
        for game-state inspection.
      responses:
        "200":
          description: Engine HTTP server is up.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthzResponse"
components:
  parameters:
    PlayerParam:
      name: player
      in: query
      required: true
      description: Race name of the player requesting the report. Must be non-blank.
      schema:
        type: string
        minLength: 1
    TurnParam:
      name: turn
      in: query
      required: false
      description: Turn number to load the report for. Defaults to 0.
      schema:
        type: integer
        minimum: 0
        default: 0
    BattleTurnParam:
      name: turn
      in: path
      required: true
      description: Turn number the battle was generated on.
      schema:
        type: integer
        minimum: 0
    BattleIDParam:
      name: uuid
      in: path
      required: true
      description: Battle identifier (RFC 4122 UUID).
      schema:
        type: string
        format: uuid
  schemas:
    HealthzResponse:
      type: object
      description: Engine liveness probe response payload.
      required:
        - status
      properties:
        status:
          type: string
          description: Always "ok" while the engine HTTP server is serving requests.
          enum:
            - ok
    StateResponse:
      type: object
      description: Summary game state returned after initialization and at each turn boundary.
      required:
        - id
        - turn
        - stage
        - player
        - finished
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of this game instance.
        turn:
          type: integer
          minimum: 0
          description: Current turn number.
        stage:
          type: integer
          minimum: 0
          description: Current stage within the turn for games that support state modification.
        player:
          type: array
          description: Summary state for each player participating in the game.
          items:
            $ref: "#/components/schemas/PlayerState"
        finished:
          type: boolean
          description: |
            True exactly once on the turn-generation response that ends the
            game; otherwise false. Server default: false. `Game Master`
            uses this flag as the sole signal to run the platform finish
            flow. The conditional logic that flips it to true lives in
            the engine's domain code and is owned by the engine
            maintainers.
    PlayerState:
      type: object
      description: Brief player state returned as part of the game state response.
      required:
        - id
        - raceName
        - planets
        - population
        - extinct
      properties:
        id:
          type: string
          format: uuid
          description: Unique player identifier within this game.
        raceName:
          type: string
          description: Name of the player's race.
        planets:
          type: integer
          minimum: 0
          description: Number of planets currently owned by the player.
        population:
          type: number
          description: Total population summed across all player planets.
        extinct:
          type: boolean
          description: True when the race has been eliminated or voluntarily quit.
    InitRequest:
      type: object
      description: Initialization request specifying the race list for a new game.
      required:
        - races
      properties:
        races:
          type: array
          description: List of participating races. Minimum 10 entries required.
          minItems: 10
          items:
            $ref: "#/components/schemas/InitRace"
    InitRace:
      type: object
      description: A single race entry in an initialization request.
      required:
        - raceName
      properties:
        raceName:
          type: string
          description: Name of the race. Must be non-blank and satisfy the entity-name format.
          minLength: 1
    BanishRequest:
      type: object
      description: |
        Request body for the admin banish endpoint. `race_name` must
        identify an existing race in the engine roster.
      required:
        - race_name
      properties:
        race_name:
          type: string
          description: Name of the race to banish. Must be non-blank.
          minLength: 1
    CommandRequest:
      type: object
      description: |
        Batch command payload. `actor` identifies the race submitting the commands.
        Each element of `cmd` is a polymorphic command object discriminated by the
        `@type` field. At least one command is required.
      required:
        - actor
        - cmd
      properties:
        actor:
          type: string
          description: Race name of the actor submitting the commands. Must be non-blank.
          minLength: 1
        cmd:
          type: array
          description: One or more commands to execute in order.
          minItems: 1
          items:
            $ref: "#/components/schemas/Command"
    UserGamesOrder:
      type: object
      description: |
        Stored player order. Returned by `PUT /api/v1/order` after successful
        validation and by `GET /api/v1/order` when fetching a previously stored
        batch. `cmd` mirrors the command list submitted by the player; entries
        carry per-command result fields (`cmdApplied`, `cmdErrorCode`) once the
        order has been processed during turn generation.
      required:
        - game_id
        - updatedAt
        - cmd
      properties:
        game_id:
          type: string
          format: uuid
          description: Identifier of the game this order belongs to.
        updatedAt:
          type: integer
          format: int64
          description: Engine-assigned UTC millisecond timestamp of the last write.
        cmd:
          type: array
          description: Commands stored as part of this order, in submission order.
          items:
            $ref: "#/components/schemas/Command"
    Command:
      type: object
      description: |
        Polymorphic game command. The `@type` field identifies the variant.
        Each variant extends the base fields with additional type-specific
        parameters documented in `pkg/model/order/order.go`.
      required:
        - "@type"
        - cmdId
      properties:
        "@type":
          $ref: "#/components/schemas/CommandType"
        cmdId:
          type: string
          format: uuid
          description: Unique command identifier (RFC 4122 UUID).
        cmdApplied:
          type: boolean
          description: Set in command-result responses; true when the command was applied.
        cmdErrorCode:
          type: integer
          description: Set in command-result responses; non-zero when the command was rejected.
    CommandType:
      type: string
      description: Discriminator identifying the game command variant carried in a `cmd` element.
      enum:
        - raceQuit
        - raceVote
        - raceRelation
        - shipClassCreate
        - shipClassMerge
        - shipClassRemove
        - shipGroupBreak
        - shipGroupLoad
        - shipGroupUnload
        - shipGroupSend
        - shipGroupUpgrade
        - shipGroupMerge
        - shipGroupDismantle
        - shipGroupTransfer
        - shipGroupJoinFleet
        - fleetMerge
        - fleetSend
        - scienceCreate
        - scienceRemove
        - planetRename
        - planetProduce
        - planetRouteSet
        - planetRouteRemove
    Report:
      type: object
      description: |
        Full game report for one player at one turn boundary. Optional array
        fields are omitted when empty.
      required:
        - version
        - turn
        - mapWidth
        - mapHeight
        - mapPlanets
        - race
        - votes
        - voteFor
        - player
      properties:
        version:
          type: integer
          minimum: 0
          description: Report format version.
        turn:
          type: integer
          minimum: 0
          description: Turn number this report covers.
        mapWidth:
          type: integer
          minimum: 0
          description: Width of the star map.
        mapHeight:
          type: integer
          minimum: 0
          description: Height of the star map.
        mapPlanets:
          type: integer
          minimum: 0
          description: Total number of planets on the map.
        race:
          type: string
          description: Race name of the report recipient.
        votes:
          type: number
          description: Fraction of alliance votes held by this race.
        voteFor:
          type: string
          description: Race name this player is currently voting for.
        player:
          type: array
          description: Diplomatic and aggregate statistics for each known player.
          items:
            $ref: "#/components/schemas/ReportPlayer"
        localScience:
          type: array
          description: Science projects owned by this race.
          items:
            $ref: "#/components/schemas/Science"
        otherScience:
          type: array
          description: Science projects owned by other known races.
          items:
            $ref: "#/components/schemas/OtherScience"
        localShipClass:
          type: array
          description: Ship classes designed by this race.
          items:
            $ref: "#/components/schemas/ShipClass"
        otherShipClass:
          type: array
          description: Ship classes belonging to other known races.
          items:
            $ref: "#/components/schemas/OtherShipClass"
        battle:
          type: array
          description: Battle summaries relevant to this turn.
          items:
            $ref: "#/components/schemas/BattleSummary"
        bombing:
          type: array
          description: Bombing events that occurred during this turn.
          items:
            $ref: "#/components/schemas/Bombing"
        incomingGroup:
          type: array
          description: Identified ship groups inbound toward this race's planets.
          items:
            $ref: "#/components/schemas/IncomingGroup"
        localPlanet:
          type: array
          description: Full state of planets owned by this race.
          items:
            $ref: "#/components/schemas/LocalPlanet"
        shipProduction:
          type: array
          description: Active ship construction status on this race's planets.
          items:
            $ref: "#/components/schemas/ShipProduction"
        route:
          type: array
          description: Cargo route configuration per planet.
          items:
            $ref: "#/components/schemas/Route"
        otherPlanet:
          type: array
          description: Partial state of planets owned by other known races.
          items:
            $ref: "#/components/schemas/OtherPlanet"
        uninhabitedPlanet:
          type: array
          description: Uninhabited planets within sensor range.
          items:
            $ref: "#/components/schemas/UninhabitedPlanet"
        unidentifiedPlanet:
          type: array
          description: Unidentified planet positions within sensor range.
          items:
            $ref: "#/components/schemas/UnidentifiedPlanet"
        localFleet:
          type: array
          description: Named fleets belonging to this race.
          items:
            $ref: "#/components/schemas/LocalFleet"
        localGroup:
          type: array
          description: Ship groups belonging to this race.
          items:
            $ref: "#/components/schemas/LocalGroup"
        otherGroup:
          type: array
          description: Ship groups belonging to other known races.
          items:
            $ref: "#/components/schemas/OtherGroup"
        unidentifiedGroup:
          type: array
          description: Unidentified ship group positions within sensor range.
          items:
            $ref: "#/components/schemas/UnidentifiedGroup"
    ReportPlayer:
      type: object
      description: Diplomatic and aggregate statistics for one player as seen in a report.
      required:
        - name
        - drive
        - weapons
        - shields
        - cargo
        - population
        - industry
        - planets
        - relation
        - votes
        - extinct
      properties:
        name:
          type: string
          description: Race name.
        drive:
          type: number
          description: Current drive technology level.
        weapons:
          type: number
          description: Current weapons technology level.
        shields:
          type: number
          description: Current shields technology level.
        cargo:
          type: number
          description: Current cargo technology level.
        population:
          type: number
          description: Total population across all planets.
        industry:
          type: number
          description: Total industrial output.
        planets:
          type: integer
          minimum: 0
          description: Number of planets owned.
        relation:
          type: string
          description: Current diplomatic relation toward this race.
        votes:
          type: number
          description: Fraction of alliance votes held.
        extinct:
          type: boolean
          description: True when the race has been eliminated or quit.
    Science:
      type: object
      description: A science project describing technology investment ratios.
      required:
        - name
        - drive
        - weapons
        - shields
        - cargo
      properties:
        name:
          type: string
          description: Science project name.
        drive:
          type: number
          description: Investment ratio for drive technology (0–1).
        weapons:
          type: number
          description: Investment ratio for weapons technology (0–1).
        shields:
          type: number
          description: Investment ratio for shields technology (0–1).
        cargo:
          type: number
          description: Investment ratio for cargo technology (0–1).
    OtherScience:
      allOf:
        - $ref: "#/components/schemas/Science"
        - type: object
          required:
            - race
          properties:
            race:
              type: string
              description: Race that owns this science project.
    ShipClass:
      type: object
      description: Design parameters for one ship class.
      required:
        - name
        - drive
        - armament
        - weapons
        - shields
        - cargo
        - mass
      properties:
        name:
          type: string
          description: Ship class name.
        drive:
          type: number
          description: Drive technology level.
        armament:
          type: integer
          minimum: 0
          description: Number of weapon mounts (ammo units).
        weapons:
          type: number
          description: Weapons technology multiplier.
        shields:
          type: number
          description: Shields technology multiplier.
        cargo:
          type: number
          description: Cargo technology multiplier.
        mass:
          type: number
          description: Computed ship mass.
    OtherShipClass:
      allOf:
        - $ref: "#/components/schemas/ShipClass"
        - type: object
          required:
            - race
          properties:
            race:
              type: string
              description: Race that owns this ship class.
    Bombing:
      type: object
      description: Record of a bombing event that occurred during turn processing.
      required:
        - planet
        - planetName
        - owner
        - attacker
        - production
        - industry
        - population
        - colonists
        - capital
        - material
        - attack
        - wiped
      properties:
        planet:
          type: integer
          minimum: 0
          description: Global planet number.
        planetName:
          type: string
          description: Planet name.
        owner:
          type: string
          description: Race name of the planet owner.
        attacker:
          type: string
          description: Race name of the attacker.
        production:
          type: string
          description: Production type active on the planet at the time of bombing.
        industry:
          type: number
          description: Industrial capacity remaining after the bombing.
        population:
          type: number
          description: Population remaining after the bombing.
        colonists:
          type: number
          description: Colonist units remaining after the bombing.
        capital:
          type: number
          description: Capital reserves remaining after the bombing.
        material:
          type: number
          description: Material reserves remaining after the bombing.
        attack:
          type: number
          description: Aggregate attack power applied during the bombing.
        wiped:
          type: boolean
          description: True when all population was eliminated by the bombing.
    BattleSummary:
      type: object
      description: |
        Identifies one battle relevant to the report recipient. Used by
        clients to render a battle marker on the map without fetching
        the full BattleReport. `planet` locates the marker; `shots`
        scales the marker stroke with the battle length.
      required:
        - id
        - planet
        - shots
      properties:
        id:
          type: string
          format: uuid
          description: Battle identifier; fetch the full report via `/api/v1/battle/{turn}/{uuid}`.
        planet:
          type: integer
          minimum: 0
          description: Planet number the battle took place on.
        shots:
          type: integer
          minimum: 0
          description: Number of shots exchanged during the battle.
    BattleReport:
      type: object
      description: |
        Full battle report. `races` and `ships` are JSON objects whose
        keys are stringified integers used to cross-reference entries
        from `protocol`: a `BattleActionReport` carries integer indices
        into both maps. The serialised key is a string because JSON
        object keys are always strings.
      required:
        - id
        - planet
        - planetName
        - races
        - ships
        - protocol
      properties:
        id:
          type: string
          format: uuid
          description: Battle identifier.
        planet:
          type: integer
          minimum: 0
          description: Planet number the battle took place on.
        planetName:
          type: string
          description: Planet name at battle start.
        races:
          type: object
          description: |
            Participating races keyed by the integer index used in
            `protocol.a` / `protocol.d`. Values are race identifiers.
          additionalProperties:
            type: string
            format: uuid
        ships:
          type: object
          description: |
            Participating ship groups keyed by the integer index used
            in `protocol.sa` / `protocol.sd`.
          additionalProperties:
            $ref: "#/components/schemas/BattleReportGroup"
        protocol:
          type: array
          description: Ordered list of shots exchanged during the battle.
          items:
            $ref: "#/components/schemas/BattleActionReport"
    BattleReportGroup:
      type: object
      description: One ship group participating in the battle.
      required:
        - race
        - className
        - tech
        - num
        - numLeft
        - loadType
        - loadQuantity
        - inBattle
      properties:
        race:
          type: string
          description: Race name of the group owner.
        className:
          type: string
          description: Ship class name; resolvable through `LocalShipClass` or `OtherShipClass`.
        tech:
          type: object
          description: Technology levels keyed by tech type name.
          additionalProperties:
            type: number
        num:
          type: integer
          minimum: 0
          description: Initial number of ships in this group.
        numLeft:
          type: integer
          minimum: 0
          description: Number of ships remaining at the end of the battle.
        loadType:
          type: string
          description: Type of cargo loaded.
        loadQuantity:
          type: number
          description: Quantity of cargo loaded.
        inBattle:
          type: boolean
          description: |
            True when the group actually fights. False groups observe
            the battle in peace state and never fire or take damage.
    BattleActionReport:
      type: object
      description: |
        One shot in the battle. Attacker and defender indices reference
        `BattleReport.races`; ship-class indices reference
        `BattleReport.ships`.
      required:
        - a
        - sa
        - d
        - sd
        - x
      properties:
        a:
          type: integer
          description: Index into `BattleReport.races` for the attacker.
        sa:
          type: integer
          description: Index into `BattleReport.ships` for the attacker's group.
        d:
          type: integer
          description: Index into `BattleReport.races` for the defender.
        sd:
          type: integer
          description: Index into `BattleReport.ships` for the defender's group.
        x:
          type: boolean
          description: True when the defender ship was destroyed by this shot.
    IncomingGroup:
      type: object
      description: An identified ship group inbound toward a planet of this race.
      required:
        - origin
        - destination
        - distance
        - speed
        - mass
      properties:
        origin:
          type: integer
          minimum: 0
          description: Planet number where this group originated.
        destination:
          type: integer
          minimum: 0
          description: Planet number this group is heading toward.
        distance:
          type: number
          description: Remaining travel distance.
        speed:
          type: number
          description: Travel speed.
        mass:
          type: number
          description: Total mass of the group.
    UnidentifiedPlanet:
      type: object
      description: Minimal sensor reading for an unidentified planet.
      required:
        - x
        - "y"
        - number
      properties:
        x:
          type: number
          description: Horizontal map coordinate.
        "y":
          type: number
          description: Vertical map coordinate.
        number:
          type: integer
          minimum: 0
          description: Global planet number.
    UninhabitedPlanet:
      allOf:
        - $ref: "#/components/schemas/UnidentifiedPlanet"
        - type: object
          description: An uninhabited planet within sensor range.
          required:
            - size
            - name
            - resources
            - capital
            - material
          properties:
            size:
              type: number
              description: Planet size.
            name:
              type: string
              description: Planet name.
            resources:
              type: number
              description: Natural resource yield (R).
            capital:
              type: number
              description: Capital reserves stored on the planet (CAP).
            material:
              type: number
              description: Material reserves stored on the planet (MAT).
    LocalPlanet:
      allOf:
        - $ref: "#/components/schemas/UninhabitedPlanet"
        - type: object
          description: Full state for a planet owned by this race.
          required:
            - industry
            - population
            - colonists
            - production
            - freeIndustry
          properties:
            industry:
              type: number
              description: Industrial capacity of the planet (I).
            population:
              type: number
              description: Population of the planet (P).
            colonists:
              type: number
              description: Number of colonists on the planet (COL).
            production:
              type: string
              description: Current production assignment.
            freeIndustry:
              type: number
              description: Unused industrial capacity available for new production (L).
    OtherPlanet:
      allOf:
        - $ref: "#/components/schemas/LocalPlanet"
        - type: object
          description: Partial planet state for a planet owned by another race.
          required:
            - owner
          properties:
            owner:
              type: string
              description: Race name of the planet owner.
    Route:
      type: object
      description: Cargo route configuration originating from one planet.
      required:
        - planet
        - route
      properties:
        planet:
          type: integer
          minimum: 0
          description: Source planet number.
        route:
          type: object
          description: |
            Mapping from destination planet number (as a string key) to the
            cargo load type being routed (MAT, CAP, COL, EMP).
          additionalProperties:
            type: string
    ShipProduction:
      type: object
      description: Active ship construction progress on one planet.
      required:
        - planet
        - class
        - cost
        - prodUsed
        - percent
        - free
      properties:
        planet:
          type: integer
          minimum: 0
          description: Planet number where construction is taking place.
        class:
          type: string
          description: Name of the ship class being built.
        cost:
          type: number
          description: Total production cost for one unit of this class.
        prodUsed:
          type: number
          description: Production units already spent on this build.
        percent:
          type: number
          description: Completion percentage of the current build.
        free:
          type: number
          description: Remaining free industrial capacity on this planet.
    LocalFleet:
      type: object
      description: A named fleet belonging to this race.
      required:
        - name
        - groups
        - destination
        - speed
        - state
      properties:
        name:
          type: string
          description: Fleet name.
        groups:
          type: integer
          minimum: 0
          description: Number of ship groups in this fleet.
        destination:
          type: integer
          minimum: 0
          description: Destination planet number.
        origin:
          type: integer
          minimum: 0
          description: Origin planet number when the fleet is in transit.
        range:
          type: number
          description: Remaining travel range when the fleet is in transit.
        speed:
          type: number
          description: Travel speed.
        state:
          type: string
          description: Fleet operational state.
    OtherGroup:
      type: object
      description: A ship group visible to this race belonging to another race.
      required:
        - number
        - class
        - tech
        - cargo
        - load
        - destination
        - speed
        - mass
      properties:
        number:
          type: integer
          minimum: 0
          description: Group identifier number.
        class:
          type: string
          description: Ship class name.
        tech:
          type: object
          description: Technology levels of this group keyed by tech type name.
          additionalProperties:
            type: number
        cargo:
          type: string
          description: Type of cargo carried by this group.
        load:
          type: number
          description: Current cargo load quantity.
        destination:
          type: integer
          minimum: 0
          description: Destination planet number.
        origin:
          type: integer
          minimum: 0
          description: Origin planet number when the group is in transit.
        range:
          type: number
          description: Remaining travel range when the group is in transit.
        speed:
          type: number
          description: Travel speed.
        mass:
          type: number
          description: Total mass of the group.
    LocalGroup:
      allOf:
        - $ref: "#/components/schemas/OtherGroup"
        - type: object
          description: A ship group belonging to this race with full ownership detail.
          required:
            - id
            - state
          properties:
            id:
              type: string
              format: uuid
              description: Unique group identifier.
            state:
              type: string
              description: Group operational state.
            fleet:
              type: string
              nullable: true
              description: Name of the fleet this group belongs to, or null if ungrouped.
    UnidentifiedGroup:
      type: object
      description: Positional reading for an unidentified ship group.
      required:
        - x
        - "y"
      properties:
        x:
          type: number
          description: Horizontal map coordinate.
        "y":
          type: number
          description: Vertical map coordinate.
    ValidationErrorResponse:
      type: object
      description: Validation error returned for malformed requests.
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable validation error message from the binding layer.
    InternalErrorResponse:
      type: object
      description: |
        Internal server error. The shape depends on the error source:
        - `{"error": "message"}` for generic runtime errors
        - `{"generic_error": "message", "code": integer}` for game-engine errors
      properties:
        error:
          type: string
          description: Generic runtime error message.
        generic_error:
          type: string
          description: Game-engine error message.
        code:
          type: integer
          description: Game-engine error code.
  responses:
    ValidationError:
      description: Request body or query parameters are invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ValidationErrorResponse"
          examples:
            validationError:
              value:
                error: "Key: 'InitRequest.Races' Error:Field validation for 'Races' failed on the 'gte' tag"
    InternalError:
      description: Internal Game Service error.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/InternalErrorResponse"
