# Copyright 2026 Lukas Bower
# SPDX-License-Identifier: Apache-2.0
# Purpose: Define the Hive Gateway REST API and selected agent protocol projections.
# Author: Lukas Bower
openapi: 3.1.0
info:
  title: Cohesix Hive Gateway
  version: 0.7.0
  description: |-
    Host-only REST gateway that projects Cohesix console/file semantics into a
    JSON API. Responses mirror OK/ERR/END semantics and enforce manifest bounds.
servers:
  - url: http://127.0.0.1:8080
paths:
  /.well-known/agent-card.json:
    get:
      summary: Subject-scoped A2A 0.3 Agent Card when compiled on.
      description: >-
        The effective A2A switch controls route registration. The returned
        skills include only currently usable CUDA/PEFT standing actions for
        the delegated subject. A card is discovery, not an admission grant.
      security:
        - requestAuthHeader: []
          delegatedTicket: []
      responses:
        "200":
          description: Bounded A2A Agent Card with JSON-RPC binding.
          content:
            application/json:
              schema:
                type: object
        "401":
          description: Request or delegated read authentication missing.
  /a2a:
    post:
      summary: A2A 0.3 JSON-RPC over the existing durable selected jobs.
      description: >-
        message/send and message/stream accept one selected data part with a
        skillId, scopeId and existing host ticket, or the exact preflight
        binding and ticket. tasks/get, tasks/cancel and tasks/resubscribe use
        the original admission ID. A task or artifact is never a native
        verification receipt. Push notifications are unsupported. Streams are
        bounded to 30 seconds and 64 events; reconnect uses the same task ID.
      security:
        - requestAuthHeader: []
          delegatedTicket: []
      parameters:
        - in: header
          name: A2A-Version
          required: false
          schema:
            type: string
            const: '0.3.0'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [jsonrpc, id, method, params]
              properties:
                jsonrpc:
                  const: '2.0'
                id:
                  oneOf:
                    - type: string
                      maxLength: 64
                    - type: integer
                method:
                  enum: [message/send, message/stream, tasks/get, tasks/cancel, tasks/resubscribe]
                params:
                  type: object
      responses:
        "200":
          description: JSON-RPC task result or bounded event stream.
          content:
            application/json:
              schema:
                type: object
            text/event-stream:
              schema:
                type: string
        "401":
          description: Request or delegated read authentication missing.
        "403":
          description: Origin or delegated authority refused.
        "413":
          description: Request exceeds 8192 bytes.
        "429":
          description: Request or stream capacity exhausted.
  /mcp:
    post:
      summary: Compiler-selected MCP 2025-11-25 Streamable HTTP JSON-RPC.
      description: >-
        Available only when both compiled gateway agent-protocol and MCP switches
        are enabled. Send one bounded JSON-RPC request with Accept listing
        application/json and text/event-stream. The request-auth credential is
        mandatory; selected discovery and job operations also require the same
        delegated ticket used by REST. Initialize before tool calls and send
        MCP-Protocol-Version 2025-11-25 on subsequent requests. Tool results
        report admission or observation, never native outcome verification.
        The selected tool schemas and authority map are compiler-generated in
        configs/generated/mcp_catalogue.json. There is no SSE stream or session.
      security:
        - requestAuthHeader: []
        - requestAuthHeader: []
          delegatedTicket: []
      parameters:
        - in: header
          name: MCP-Protocol-Version
          required: false
          description: Required after initialization; selected revision is 2025-11-25.
          schema:
            type: string
            const: '2025-11-25'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [jsonrpc, method]
              properties:
                jsonrpc:
                  const: '2.0'
                id:
                  oneOf:
                    - type: string
                      maxLength: 64
                    - type: integer
                method:
                  type: string
                params:
                  type: object
      responses:
        '200':
          description: One bounded JSON-RPC result or error.
        '202':
          description: Accepted initialized notification, without a body.
        '400':
          description: Unsupported post-initialization protocol revision.
        '401':
          description: Gateway request authentication is missing or invalid.
        '403':
          description: Invalid Origin or refused delegated authority.
        '405':
          description: Authenticated GET or DELETE; this server provides no SSE stream or session.
        '406':
          description: Missing required MCP Accept media types.
        '413':
          description: Request exceeds 8192 bytes.
        '415':
          description: Request content type is not application/json.
        '429':
          description: All 16 MCP request slots are occupied.
  /v1/identity/exchange:
    post:
      summary: Exchange an enrolled external credential for a finite gateway-only ticket.
      description: >-
        Requires request authentication, one generated mapping id and a signed
        JWT credential. Local uid assertions and client-selected roles, scopes,
        keys, URLs or lifetime overrides are refused. The host applies pinned
        keys and exact generated policy; no target or provider request occurs.
        Body maximum is 9216 bytes and at most four verifications run concurrently.
        Returned authority is gateway_enforced and does not prove execution.
      security:
        - bearerAuth: []
        - requestAuthHeader: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [mapping_id, credential]
              properties:
                mapping_id:
                  type: string
                  minLength: 1
                  maxLength: 128
                credential:
                  type: string
                  minLength: 1
                  maxLength: 8192
                  writeOnly: true
      responses:
        "200":
          description: Verified mapped credential, subject to gateway policy, finite lifetime and quotas.
          headers:
            Cache-Control:
              schema:
                const: no-store
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [schema, status, authoritative, identity_class, mapping_id, provider_graph_sha256, credential_sha256, expires_unix_s, ticket]
                properties:
                  schema:
                    const: cohesix-identity-exchange/v1
                  status:
                    const: OK
                  authoritative:
                    const: false
                  identity_class:
                    const: gateway_enforced
                  mapping_id:
                    type: string
                  provider_graph_sha256:
                    type: string
                    pattern: '^[0-9a-f]{64}$'
                  credential_sha256:
                    type: string
                    pattern: '^[0-9a-f]{64}$'
                  expires_unix_s:
                    type: integer
                    minimum: 1
                  ticket:
                    type: string
                    maxLength: 224
        "400":
          description: Malformed or bounded request.
        "401":
          description: Missing or invalid gateway request authentication.
        "403":
          description: Disabled, unmapped, forged, stale, overbroad or otherwise refused identity.
        "413":
          description: HTTP request body exceeds the route bound.
        "429":
          description: All four verification slots are occupied.
        "503":
          description: Identity clock or verification worker unavailable.
  /v1/meta/providers:
    get:
      summary: Admin-only compiler-owned provider/action and integration-surface contracts.
      description: Registration grants no authority and proves no live execution. The full registry includes enrolled identity mappings and requires request authentication plus a delegated read scope for /proc/providers/registry unless explicit single-caller read compatibility applies.
      security:
        - bearerAuth: []
          delegatedTicket: []
      responses:
        "200":
          description: Exact compiled registry with its stable integration graph hash and source bindings.
          content:
            application/json:
              schema:
                type: object
                required: [schema, graph_schema, graph_sha256, source_sha256, resolved_manifest_sha256, contract]
                properties:
                  schema:
                    const: cohesix-provider-registry/v1
                  graph_schema:
                    const: host-integration-dependency/v1
                  graph_sha256:
                    type: string
                    pattern: '^[a-f0-9]{64}$'
                  source_sha256:
                    type: string
                    pattern: '^[a-f0-9]{64}$'
                  resolved_manifest_sha256:
                    type: string
                    pattern: '^[a-f0-9]{64}$'
                  contract:
                    type: object
                    description: Compiler-owned provider families, actions, exact profiles and integration surfaces.
  /v1/meta/bounds:
    get:
      summary: Manifest-derived bounds, paths, and optional Worker declarations.
      responses:
        "200":
          description: Boundaries derived from the active manifest.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BoundsResponse"
  /v1/meta/status:
    get:
      description: Non-public reads require request authentication and a delegated Read or ReadWrite scope. Unknown paths are admin-only; ticket-scoped reads require delegated identity even in explicit read compatibility mode.
      security:
        - bearerAuth: []
          delegatedTicket: []
      summary: Gateway connection, backend class, optional Worker acceptance, and broker counters.
      responses:
        "200":
          description: Runtime gateway status and broker metrics.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayStatusResponse"
  /v1/fs/ls:
    get:
      description: Non-public reads require request authentication and a delegated Read or ReadWrite scope. Unknown paths are admin-only; ticket-scoped reads require delegated identity even in explicit read compatibility mode.
      security:
        - bearerAuth: []
          delegatedTicket: []
      summary: List directory entries (LS).
      parameters:
        - in: query
          name: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: List operation response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "400":
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "429":
          description: Gateway broker queue backpressure.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "503":
          description: Gateway transport unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "504":
          description: Gateway broker response timed out.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
  /v1/fs/cat:
    get:
      description: Non-public reads require request authentication and a delegated Read or ReadWrite scope. Unknown paths are admin-only; ticket-scoped reads require delegated identity even in explicit read compatibility mode.
      security:
        - bearerAuth: []
          delegatedTicket: []
      summary: Read file contents (CAT).
      parameters:
        - in: query
          name: path
          required: true
          schema:
            type: string
        - in: query
          name: max_bytes
          required: true
          schema:
            type: integer
            minimum: 1
      responses:
        "200":
          description: Read operation response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "400":
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "429":
          description: Gateway broker queue backpressure.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "503":
          description: Gateway transport unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "504":
          description: Gateway broker response timed out.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
  /v1/fs/tail:
    get:
      description: Non-public reads require request authentication and a delegated Read or ReadWrite scope. Unknown paths are admin-only; ticket-scoped reads require delegated identity even in explicit read compatibility mode.
      security:
        - bearerAuth: []
          delegatedTicket: []
      summary: Tail file contents (TAIL).
      parameters:
        - in: query
          name: path
          required: true
          schema:
            type: string
        - in: query
          name: max_bytes
          required: true
          schema:
            type: integer
            minimum: 1
        - in: query
          name: lines
          required: false
          description: Optional tail line count. Values must be between 1 and 256.
          schema:
            type: integer
            minimum: 1
            maximum: 256
      responses:
        "200":
          description: Tail operation response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "400":
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "429":
          description: Gateway broker queue backpressure.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "503":
          description: Gateway transport unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "504":
          description: Gateway broker response timed out.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
  /v1/fs/echo:
    post:
      summary: Append a single line (ECHO).
      security:
        - bearerAuth: []
          delegatedTicket: []
        - requestAuthHeader: []
          delegatedTicket: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EchoRequest"
      responses:
        "200":
          description: >
            Echo operation response. A successful queen telemetry segment-control
            write may return the provider-assigned segment ID as the sole `lines`
            entry; clients must retain `/latest` as a compatibility fallback.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "401":
          description: Missing or invalid request authentication token.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "403":
          description: Missing, invalid, expired or insufficient delegated capability (EPERM).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "400":
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "429":
          description: Gateway broker queue backpressure.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "503":
          description: Gateway transport unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "504":
          description: Gateway broker response timed out.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
  /v1/fs/echo-batch:
    post:
      summary: Append 1 to 8 ordered host-ticket result lines in one transport activation.
      description: >
        This authenticated route is limited to `/host/tickets/status` and
        `/host/tickets/deadletter`. It preserves per-line ECHO validation and
        order while amortizing one bounded guest command batch. It is never
        replayed after a partial transport failure.
      security:
        - bearerAuth: []
          delegatedTicket: []
        - requestAuthHeader: []
          delegatedTicket: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EchoBatchRequest"
      responses:
        "200":
          description: All ordered appends completed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "403":
          description: Missing, invalid, expired or insufficient delegated capability (EPERM).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "400":
          description: Invalid path, line, or batch bound.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "401":
          description: Missing or invalid request authentication token.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "429":
          description: Gateway broker queue backpressure.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "503":
          description: Gateway transport unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
        "504":
          description: Gateway broker response timed out.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GatewayResponse"
  /v1/jobs:
    post:
      summary: Reserve and submit one selected durable job.
      description: >-
        The private standing ledger reserves the exact binding before a root
        ticket write. A lost or uncertain response is reconciled by the same
        admission id; callers must not submit a new effect identity.
      security:
        - bearerAuth: []
          delegatedTicket: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [binding, ticket]
              properties:
                binding:
                  $ref: "#/components/schemas/SelectedJobBinding"
                ticket:
                  type: object
                  description: Existing exact host-ticket/v1 or host-ticket/v2 request without caller admission.
      responses:
        "200":
          description: Exact admission already retained; no effect replay.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SelectedJobResponse"
        "202":
          description: Target ticket write acknowledged; native outcome remains pending.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SelectedJobResponse"
        "403":
          description: Delegation, scope, current facts or budget refused.
        "409":
          description: Target write outcome uncertain; reconcile original admission id.
        "503":
          description: Current native or target facts unavailable.
  /v1/jobs/approved/{scope_id}/start:
    post:
      summary: Start one selected service scope with a stable request identity.
      description: >-
        The gateway derives the systemd.restart ticket from the operator-selected
        standing scope and current native facts. Only that scope's subject may
        start it. A repeated request ID returns the retained admission without
        replaying an uncertain write. The admission ID is mac-<request_id>.
        This route does not admit GPU workloads or MLX releases.
      security:
        - bearerAuth: []
          delegatedTicket: []
        - requestAuthHeader: []
          delegatedTicket: []
      parameters:
        - name: scope_id
          in: path
          required: true
          schema:
            type: string
            minLength: 1
            maxLength: 128
            pattern: '^(?!-)(?!.*\.\.)[A-Za-z0-9._-]+$'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [request_id]
              properties:
                request_id:
                  type: string
                  minLength: 1
                  maxLength: 96
                  pattern: '^(?!-)(?!.*\.\.)[A-Za-z0-9._-]+$'
      responses:
        "200":
          description: Original admission retained; no effect replay.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SelectedJobResponse"
        "202":
          description: Target ticket write acknowledged; native outcome remains pending.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SelectedJobResponse"
        "400":
          description: Malformed request identity or target.
        "403":
          description: Delegation, scope, revocation, facts or budget refused.
        "409":
          description: Reused identity conflict or uncertain original write; reconcile its admission ID.
        "503":
          description: Current native or target facts unavailable.
  /v1/jobs/{admission_id}:
    get:
      summary: Read retained execution and independent result delivery state.
      security:
        - bearerAuth: []
          delegatedTicket: []
      parameters:
        - $ref: "#/components/parameters/AdmissionId"
      responses:
        "200":
          description: One retained job record.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SelectedJobRecord"
        "404":
          description: Unknown or inaccessible admission id.
  /v1/jobs/{admission_id}/cancel:
    post:
      summary: Record a cancellation request without asserting termination.
      security:
        - bearerAuth: []
          delegatedTicket: []
      parameters:
        - $ref: "#/components/parameters/AdmissionId"
      responses:
        "202":
          description: Cancellation requested; existing native work may continue.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SelectedJobRecord"
  /v1/jobs/{admission_id}/reconcile:
    post:
      summary: Observe exact target results without submitting the effect again.
      security:
        - bearerAuth: []
          delegatedTicket: []
      parameters:
        - $ref: "#/components/parameters/AdmissionId"
      responses:
        "200":
          description: Retained job and bounded matching target results.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SelectedJobReconciliation"
        "503":
          description: Target result read unavailable; absence of effect is not established.
  /v1/standing/scopes/available:
    get:
      summary: List the current delegated subject's available approved service scopes.
      description: >-
        The bounded list excludes other subjects, revoked or expired scopes and
        exhausted budgets. A listed scope is not a grant; start rechecks native
        facts and durable standing authority before submitting a ticket.
      security:
        - bearerAuth: []
          delegatedTicket: []
        - requestAuthHeader: []
          delegatedTicket: []
      responses:
        "200":
          description: Current subject-filtered service choices.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [schema, scopes]
                properties:
                  schema:
                    const: cohesix-available-scopes/v1
                  scopes:
                    type: array
                    maxItems: 16
                    items:
                      type: object
                      additionalProperties: false
                      required: [id, action, target]
                      properties:
                        id:
                          type: string
                        action:
                          const: systemd.restart
                        target:
                          type: string
        "403":
          description: Missing or invalid delegated read authority.
        "503":
          description: Standing ledger or authority clock unavailable.
  /v1/standing/scopes/{scope_id}/inspect:
    post:
      summary: Inspect a scope and its retained cumulative budget.
      security:
        - bearerAuth: []
          delegatedTicket: []
      parameters:
        - $ref: "#/components/parameters/ScopeId"
      responses:
        "200":
          description: Private standing scope and budget snapshot.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StandingScopeStatus"
  /v1/standing/scopes/{scope_id}/revoke:
    post:
      summary: Durably revoke future dispatch under a standing scope.
      security:
        - bearerAuth: []
          delegatedTicket: []
      parameters:
        - $ref: "#/components/parameters/ScopeId"
      responses:
        "200":
          description: Revoked scope and retained budget; existing work remains unresolved until observed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StandingScopeStatus"
  /v1/openapi.yaml:
    get:
      summary: OpenAPI 3.1 specification.
      responses:
        "200":
          description: OpenAPI specification (YAML).
          content:
            application/yaml:
              schema:
                type: string
  /docs:
    get:
      summary: Swagger UI.
      responses:
        "200":
          description: Swagger UI HTML.
          content:
            text/html:
              schema:
                type: string
components:
  parameters:
    AdmissionId:
      in: path
      name: admission_id
      required: true
      schema:
        type: string
        minLength: 1
        maxLength: 128
    ScopeId:
      in: path
      name: scope_id
      required: true
      schema:
        type: string
        minLength: 1
        maxLength: 128
  securitySchemes:
    delegatedTicket:
      type: apiKey
      in: header
      name: x-cohesix-ticket
      description: >
        Required together with request authentication on mutations and non-public reads. The
        gateway verifies the existing ticket MAC, subject, scopes and quotas
        under its configured transport authority ceiling. Identity is
        gateway_enforced; the VM authenticates the gateway console session.
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: opaque
      description: >
        Required for mutating endpoints and non-public reads. Supply `Authorization: Bearer <token>`.
    requestAuthHeader:
      type: apiKey
      in: header
      name: x-cohesix-auth
      description: >
        Alternative to bearer auth for mutating endpoints.
  schemas:
    SelectedJobBinding:
      type: object
      additionalProperties: false
      required: [schema, scope_id, admission_id, ticket_id, idempotency_key, subject, action, target, input_sha256, policy_sha256, state_epoch, resource_generation, deadline_unix_ms, units, attempt]
      properties:
        schema: {const: cohesix-job-binding/v1}
        scope_id: {type: string}
        admission_id: {type: string}
        ticket_id: {type: string}
        idempotency_key: {type: string}
        subject: {type: string}
        action: {type: string, enum: [gpu.workload.submit, systemd.restart]}
        target: {type: string}
        input_sha256: {type: string, pattern: '^[0-9a-f]{64}$'}
        policy_sha256: {type: string, pattern: '^[0-9a-f]{64}$'}
        state_epoch: {type: integer, minimum: 1}
        resource_generation: {type: integer, minimum: 1}
        deadline_unix_ms: {type: integer, minimum: 1}
        units: {const: 1}
        attempt: {type: integer, minimum: 1}
    SelectedJobRecord:
      type: object
      required: [binding, intent_sha256, scope_generation, decision_expires_unix_ms, reserved_unix_ms, execution, delivery, cancel_requested]
      properties:
        binding:
          $ref: "#/components/schemas/SelectedJobBinding"
        intent_sha256: {type: string, pattern: '^[0-9a-f]{64}$'}
        scope_generation: {type: integer, minimum: 1}
        decision_expires_unix_ms: {type: integer, minimum: 1}
        reserved_unix_ms: {type: integer, minimum: 1}
        dispatched_unix_ms: {type: [integer, 'null']}
        execution: {type: string, enum: [reserved, dispatching, uncertain, confirmed, refused_no_effect]}
        delivery: {type: string, enum: [pending, acknowledged]}
        result_sha256: {type: [string, 'null']}
        cancel_requested: {type: boolean}
    SelectedJobResponse:
      type: object
      required: [schema, record, submission]
      properties:
        schema: {const: cohesix-selected-job-response/v1}
        record:
          $ref: "#/components/schemas/SelectedJobRecord"
        submission: {type: string, enum: [existing, target_write_ack]}
    SelectedJobReconciliation:
      type: object
      required: [schema, record, target_results, target_result_sha256, effect_replay_allowed]
      properties:
        schema: {const: cohesix-selected-job-reconciliation/v1}
        record:
          $ref: "#/components/schemas/SelectedJobRecord"
        target_results: {type: array, maxItems: 64, items: {type: object}}
        target_result_sha256: {type: array, maxItems: 64, items: {type: string, pattern: '^[0-9a-f]{64}$'}}
        effect_replay_allowed: {const: false}
    StandingScopeStatus:
      type: object
      required: [scope, budget]
      properties:
        scope: {type: object}
        budget: {type: object}
    GatewayResponse:
      type: object
      required:
        - status
        - verb
        - path
        - end
      properties:
        status:
          type: string
          enum: ["OK", "ERR"]
        verb:
          type: string
        path:
          type: string
        end:
          type: boolean
        lines:
          type: array
          items:
            type: string
        bytes:
          type: integer
          minimum: 0
        error:
          type: string
    EchoRequest:
      type: object
      required:
        - path
      properties:
        path:
          type: string
        line:
          type: string
    EchoBatchRequest:
      type: object
      required:
        - path
        - lines
      properties:
        path:
          type: string
          enum:
            - /host/tickets/status
            - /host/tickets/deadletter
        lines:
          type: array
          minItems: 1
          maxItems: 8
          items:
            type: string
    BoundsResponse:
      type: object
      required:
        - manifest_sha256
        - secure9p
        - console
        - paths
        - control_plane
        - policy
        - observability
      properties:
        manifest_sha256:
          type: string
        secure9p:
          type: object
          required: [msize, walk_depth]
          properties:
            msize:
              type: integer
            walk_depth:
              type: integer
        console:
          type: object
          required:
            - max_line_len
            - max_path_len
            - max_json_len
            - max_id_len
            - max_echo_len
            - max_ticket_len
          properties:
            max_line_len:
              type: integer
            max_path_len:
              type: integer
            max_json_len:
              type: integer
            max_id_len:
              type: integer
            max_echo_len:
              type: integer
            max_ticket_len:
              type: integer
        paths:
          type: object
          required:
            - queen_ctl
            - queen_lifecycle_ctl
            - queen_schedule_ctl
            - queen_lease_ctl
            - queen_export_ctl
            - policy_ctl
            - log
          properties:
            queen_ctl:
              type: string
            queen_lifecycle_ctl:
              type: string
            queen_schedule_ctl:
              type: string
            queen_lease_ctl:
              type: string
            queen_export_ctl:
              type: string
            policy_ctl:
              type: string
            log:
              type: string
        control_plane:
          type: object
          required: [schedule, lease, export]
          properties:
            schedule:
              type: object
              required: [enable, queue_max_entries, ctl_max_bytes]
              properties:
                enable:
                  type: boolean
                queue_max_entries:
                  type: integer
                ctl_max_bytes:
                  type: integer
            lease:
              type: object
              required: [enable, active_max_entries, preemptions_max_entries, ctl_max_bytes]
              properties:
                enable:
                  type: boolean
                active_max_entries:
                  type: integer
                preemptions_max_entries:
                  type: integer
                ctl_max_bytes:
                  type: integer
            export:
              type: object
              required: [enable, ctl_max_bytes]
              properties:
                enable:
                  type: boolean
                ctl_max_bytes:
                  type: integer
        policy:
          type: object
          required: [enable, queue_max_entries, queue_max_bytes, ctl_max_bytes]
          properties:
            enable:
              type: boolean
            queue_max_entries:
              type: integer
            queue_max_bytes:
              type: integer
            ctl_max_bytes:
              type: integer
        observability:
          type: object
          required: [proc_schedule, proc_lease]
          properties:
            proc_schedule:
              type: object
              required: [summary, queue, summary_bytes, queue_bytes]
              properties:
                summary:
                  type: boolean
                queue:
                  type: boolean
                summary_bytes:
                  type: integer
                queue_bytes:
                  type: integer
            proc_lease:
              type: object
              required: [summary, active, preemptions, summary_bytes, active_bytes, preemptions_bytes]
              properties:
                summary:
                  type: boolean
                active:
                  type: boolean
                preemptions:
                  type: boolean
                summary_bytes:
                  type: integer
                active_bytes:
                  type: integer
                preemptions_bytes:
                  type: integer
        worker_runtime:
          $ref: "#/components/schemas/WorkerRuntimeBounds"
    WorkerRuntimeBounds:
      type: object
      description: >
        Optional compiler-generated declaration bounds. Absence means unknown;
        this object is not runtime READY or target proof.
      required:
        - roles
        - task_abi_schema
        - task_abi_version
        - worker_observation_schema
        - worker_integration_evidence_schema
        - maximum_live_tasks
        - canonical_telemetry_template
        - shard_bits
        - legacy_worker_alias
      properties:
        roles:
          type: array
          items:
            $ref: "#/components/schemas/WorkerRoleBounds"
        task_abi_schema:
          type: string
        task_abi_version:
          type: integer
          minimum: 1
        worker_observation_schema:
          type: string
        worker_integration_evidence_schema:
          type: string
        maximum_live_tasks:
          type: integer
          minimum: 1
        canonical_telemetry_template:
          type: string
          const: /shard/<label>/worker/<id>/telemetry
        shard_bits:
          type: integer
          minimum: 1
          maximum: 8
        legacy_worker_alias:
          type: boolean
    WorkerRoleBounds:
      type: object
      required: [role, declaration, executable_slots]
      properties:
        role:
          type: string
          enum: [worker-heartbeat, worker-gpu, worker-bus, worker-lora]
        declaration:
          type: string
          enum: [executable, model-only]
        executable_slots:
          type: integer
          minimum: 0
    DelegationStatus:
      type: object
      required: [identity_class, writer_epoch, cache_entries, cache_capacity, cache_hits, cache_misses, refusals, audit_records, audit_emit_ns]
      properties:
        identity_class:
          const: gateway_enforced
        writer_epoch:
          type: integer
          minimum: 1
        cache_entries:
          type: integer
          minimum: 0
        cache_capacity:
          type: integer
          minimum: 1
        cache_hits:
          type: integer
          minimum: 0
        cache_misses:
          type: integer
          minimum: 0
        refusals:
          type: integer
          minimum: 0
        audit_records:
          type: integer
          minimum: 0
        audit_emit_ns:
          type: integer
          minimum: 0
          description: Cumulative synchronous gateway audit emission time; excludes downstream log storage.
    GatewayStatusResponse:
      type: object
      required:
        - connected
        - target_host
        - target_port
        - reconnects
        - connects
        - broker
      properties:
        authority:
          oneOf:
            - type: "null"
            - $ref: "#/components/schemas/DelegationStatus"
        connected:
          type: boolean
          description: Console connection only; never target execution proof.
        target_host:
          type: string
          minLength: 1
          maxLength: 253
          description: Normalized configured backend TCP target, not the REST bind host.
        target_port:
          type: integer
          minimum: 1
          maximum: 65535
          description: Configured backend TCP target port, not the REST bind port.
        backend_class:
          type: string
          enum: [host-model, console-projection, unknown]
        worker_acceptance:
          $ref: "#/components/schemas/WorkerAcceptanceSummary"
        worker_acceptance_diagnostic:
          $ref: "#/components/schemas/WorkerAcceptanceDiagnostic"
        last_error:
          type: string
        last_change_unix_ms:
          type: integer
          minimum: 0
        reconnects:
          type: integer
          minimum: 0
        connects:
          type: integer
          minimum: 0
        broker:
          $ref: "#/components/schemas/BrokerStatusResponse"
    WorkerAcceptanceSummary:
      type: object
      description: >
        Redacted projection produced only after shared-library validation of a
        bounded local acceptance record. It adds no authority route.
      required:
        - schema
        - record_kind
        - evidence_sha256
        - verdict
        - target
        - execution_proof
        - target_session
        - topology_sha256
      properties:
        schema:
          type: string
          enum: [cohesix-worker-task-evidence/v1]
        record_kind:
          type: string
          enum: [target-component]
        evidence_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
        verdict:
          type: string
          enum: [PASS, FAIL]
        target:
          type: string
          enum: [qemu, pi4]
        execution_proof:
          type: string
          enum: [none, qemu, fresh-pi]
        target_session:
          $ref: "#/components/schemas/TargetSessionSummary"
        topology_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
        workers:
          type: array
          items:
            $ref: "#/components/schemas/WorkerAcceptanceRoleSummary"
    WorkerAcceptanceRoleSummary:
      type: object
      required:
        - role
        - lifecycle
        - artifact
        - receipt
        - execution_proof
        - slot
        - lease_epoch
        - supervisor_generation
        - cap_generation
        - image_sha256
        - ready_sequence
        - completion_sequence
        - core
        - scheduling_context
        - object_inventory
      properties:
        role:
          type: string
          enum: [worker-heartbeat, worker-gpu, worker-lora]
        lifecycle:
          type: string
          enum: [absent, queued, starting, ready, closing, faulted, terminal]
        artifact:
          type: string
          enum: [missing, verified, mismatch]
        receipt:
          type: string
          enum: [none, pending, confirmed, rejected, stale]
        execution_proof:
          type: string
          enum: [none, host-model, qemu, fresh-pi]
        slot:
          type: integer
          minimum: 0
        lease_epoch:
          type: integer
          minimum: 1
        supervisor_generation:
          type: integer
          minimum: 1
        cap_generation:
          type: integer
          minimum: 1
        image_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
        ready_sequence:
          type: integer
          minimum: 0
        completion_sequence:
          type: integer
          minimum: 0
        core:
          type: integer
          minimum: 0
          maximum: 3
        scheduling_context:
          $ref: "#/components/schemas/WorkerSchedulingContextSummary"
        object_inventory:
          $ref: "#/components/schemas/KernelObjectInventorySummary"
    TargetSessionSummary:
      type: object
      required:
        - target_session_sha256
        - manifest_sha256
        - root_image_sha256
        - worker_archive_sha256
        - worker_image_manifest_sha256
        - worker_abi_sha256
      properties:
        target_session_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
        manifest_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
        root_image_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
        worker_archive_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
        worker_image_manifest_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
        worker_abi_sha256:
          type: string
          pattern: "^[0-9a-f]{64}$"
    WorkerSchedulingContextSummary:
      type: object
      description: |-
        A passive Worker owns no scheduling context and reports exact 0/0.
        An active Worker reports positive values; the runtime additionally
        enforces budget_us <= period_us.
      required: [budget_us, period_us]
      properties:
        budget_us:
          type: integer
          minimum: 0
        period_us:
          type: integer
          minimum: 0
      oneOf:
        - properties:
            budget_us: {const: 0}
            period_us: {const: 0}
        - properties:
            budget_us: {minimum: 1}
            period_us: {minimum: 1}
    KernelObjectInventorySummary:
      type: object
      additionalProperties: false
      required:
        - tcbs
        - scheduling_contexts
        - reply_objects
        - vspaces
        - cnodes
        - page_tables
        - asids
        - frames
        - endpoints
        - notifications
        - fault_caps
        - timeout_fault_caps
        - cspace_slots
        - untyped_bytes
      properties:
        tcbs: {type: integer, minimum: 0}
        scheduling_contexts: {type: integer, minimum: 0}
        reply_objects: {type: integer, minimum: 0}
        vspaces: {type: integer, minimum: 0}
        cnodes: {type: integer, minimum: 0}
        page_tables: {type: integer, minimum: 0}
        asids: {type: integer, minimum: 0}
        frames: {type: integer, minimum: 0}
        endpoints: {type: integer, minimum: 0}
        notifications: {type: integer, minimum: 0}
        fault_caps: {type: integer, minimum: 0}
        timeout_fault_caps: {type: integer, minimum: 0}
        cspace_slots: {type: integer, minimum: 0}
        untyped_bytes: {type: integer, minimum: 0}
    WorkerAcceptanceDiagnostic:
      type: object
      required: [code]
      properties:
        code:
          type: string
          enum:
            - not-configured
            - incomplete-configuration
            - unsafe-root
            - outside-root
            - symlink-traversal
            - not-regular-file
            - record-too-large
            - read-failed
            - invalid-evidence
            - invalid-target-session
            - target-session-mismatch
            - manifest-mismatch
            - unsupported-record-kind
    BrokerStatusResponse:
      type: object
      required:
        - control_waiters
        - telemetry_waiters
        - control_waiters_high_water
        - telemetry_waiters_high_water
        - control_checkouts
        - telemetry_checkouts
        - pool_exhausted
        - checkout_retries
        - timeout_rejections
        - telemetry_yields
        - proc_cache_hits
        - proc_cache_misses
        - proc_cache_evictions
        - control_write_retryable_errors
        - control_write_retries
        - control_write_retry_sleep_ms
        - control_write_retry_exhaustions
        - control_write_success_after_retry
        - relay_queue_depth
        - relay_deduped
        - relay_remote_write_failures
      properties:
        control_waiters:
          type: integer
          minimum: 0
        telemetry_waiters:
          type: integer
          minimum: 0
        control_waiters_high_water:
          type: integer
          minimum: 0
        telemetry_waiters_high_water:
          type: integer
          minimum: 0
        control_checkouts:
          type: integer
          minimum: 0
        telemetry_checkouts:
          type: integer
          minimum: 0
        pool_exhausted:
          type: integer
          minimum: 0
        checkout_retries:
          type: integer
          minimum: 0
        timeout_rejections:
          type: integer
          minimum: 0
        telemetry_yields:
          type: integer
          minimum: 0
        proc_cache_hits:
          type: integer
          minimum: 0
        proc_cache_misses:
          type: integer
          minimum: 0
        proc_cache_evictions:
          type: integer
          minimum: 0
        control_write_retryable_errors:
          type: integer
          minimum: 0
        control_write_retries:
          type: integer
          minimum: 0
        control_write_retry_sleep_ms:
          type: integer
          minimum: 0
        control_write_retry_exhaustions:
          type: integer
          minimum: 0
        control_write_success_after_retry:
          type: integer
          minimum: 0
        relay_queue_depth:
          type: integer
          minimum: 0
        relay_deduped:
          type: integer
          minimum: 0
        relay_remote_write_failures:
          type: integer
          minimum: 0
