{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Koobique Client API",
    "version": "0.1.0-draft",
    "description": "PROPOSED reviewable contract, not an implemented backend. Independent of MCU KQIP0.2. No live server is supplied. Security scheme is a placeholder for a separately qualified user/session credential lifecycle, not a definition of token issuance."
  },
  "security": [
    {
      "userSession": []
    }
  ],
  "paths": {
    "/v0/installations/{installation_id}/snapshot": {
      "parameters": [
        {
          "name": "installation_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "Installation scope; validated against current principal rights."
        }
      ],
      "get": {
        "operationId": "getSnapshot",
        "summary": "Get coherent state and event cursor",
        "responses": {
          "200": {
            "description": "Snapshot and cursor from the same boundary.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Snapshot"
                }
              }
            }
          },
          "401": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v0/installations/{installation_id}/events": {
      "parameters": [
        {
          "name": "installation_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "Installation scope; validated against current principal rights."
        }
      ],
      "get": {
        "operationId": "resumeEvents",
        "summary": "Resume authorized events after snapshot cursor",
        "description": "Native streaming HTTP client supplies Authorization header and mandatory after cursor. SSE id equals JSON Event.cursor; data is one JSON Event. Cursor replay is ordered by server append position, not event time. Replay/live handoff is gap-free. Validate cursor before headers: missing/expired/foreign-generation history returns HTTP410 RESYNC_REQUIRED. If gap/auth change is detected after HTTP200, send RESYNC_REQUIRED/AUTHORIZATION_CHANGED when safe, then close; client must obtain a new snapshot. Lost connection never repeats an intent automatically. No credentials in URL.",
        "parameters": [
          {
            "name": "after",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            },
            "description": "Opaque snapshot or last applied event cursor. Persist only after applying the event."
          }
        ],
        "responses": {
          "200": {
            "description": "SSE stream. Each data payload conforms to components.schemas.Event.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "410": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "x-sse-event-schema": {
          "$ref": "#/components/schemas/Event"
        }
      }
    },
    "/v0/installations/{installation_id}/intents": {
      "parameters": [
        {
          "name": "installation_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "Installation scope; validated against current principal rights."
        }
      ],
      "post": {
        "operationId": "createUserIntent",
        "summary": "Submit an explicit user intent",
        "description": "Atomically validate current rights and store canonical request+idempotency record+outbox before RECEIVED. Scope Idempotency-Key by authenticated principal and installation. Same key and same canonical request returns same intent without a second execution; changed request gives409. Retention is at least30days, advertised by retention header; after expiry an old request is not retried automatically. Current authorization is checked before returning cached history and again before dispatch. One intent maps to a fixed execution sequence per target/boot/fence; retries do not refresh snapshot, deadline or authority. Idempotency does not authorize an action. Content-Type application/json only; max body16KiB; duplicate JSON keys rejected.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Random UUID stable for retries of this exact user intent."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserIntent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Exact authorized retry: same intent record, possibly advanced status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntentRecord"
                }
              }
            }
          },
          "202": {
            "description": "Durably RECEIVED; execution not promised.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntentRecord"
                }
              }
            },
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "description": "Same-origin URL to intent record."
              },
              "Idempotency-Retention-Until": {
                "schema": {
                  "type": "string",
                  "format": "date-time"
                },
                "description": "Minimum durable dedup retention boundary."
              }
            }
          },
          "400": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v0/installations/{installation_id}/intents/{intent_id}": {
      "parameters": [
        {
          "name": "installation_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "Installation scope; validated against current principal rights."
        },
        {
          "name": "intent_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "Intent record identifier."
        }
      ],
      "get": {
        "operationId": "getIntent",
        "summary": "Read historical intent and independent effect evidence",
        "responses": {
          "200": {
            "description": "Authorized historical result; current target state is obtained from snapshot/events.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntentRecord"
                }
              }
            }
          },
          "401": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Problem response; never implies a physical action did or did not happen.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "userSession": {
        "type": "http",
        "scheme": "bearer",
        "description": "Installation-scoped user session credential over authenticated HTTPS. Separate from MCU mTLS peer identity and owner-authority/recovery keys. No token issuance or hardware protection is claimed."
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599
          },
          "code": {
            "enum": [
              "INVALID_REQUEST",
              "UNAUTHENTICATED",
              "FORBIDDEN",
              "NOT_FOUND",
              "IDEMPOTENCY_CONFLICT",
              "STATE_CONFLICT",
              "RESYNC_REQUIRED",
              "RATE_LIMITED",
              "UNAVAILABLE"
            ]
          },
          "detail": {
            "type": "string",
            "maxLength": 2048
          },
          "request_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code",
          "detail",
          "request_id"
        ],
        "additionalProperties": false
      },
      "ExpectedState": {
        "type": "object",
        "properties": {
          "snapshot_id": {
            "type": "string",
            "format": "uuid"
          },
          "node_boot_id": {
            "type": "string",
            "format": "uuid"
          },
          "controller_fence": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,19})$",
            "description": "Unsigned 64-bit decimal. Runtime must reject values >18446744073709551615; no JSON float conversion."
          },
          "manual_revision": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,19})$",
            "description": "Unsigned 64-bit decimal. Runtime must reject values >18446744073709551615; no JSON float conversion."
          },
          "output_revision": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,19})$",
            "description": "Unsigned 64-bit decimal. Runtime must reject values >18446744073709551615; no JSON float conversion."
          }
        },
        "required": [
          "snapshot_id",
          "node_boot_id",
          "controller_fence",
          "manual_revision",
          "output_revision"
        ],
        "additionalProperties": false
      },
      "UserIntent": {
        "type": "object",
        "properties": {
          "target_id": {
            "type": "string",
            "format": "uuid"
          },
          "operation": {
            "enum": [
              "SET",
              "RELEASE_MANUAL"
            ]
          },
          "value": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "expected": {
            "$ref": "#/components/schemas/ExpectedState"
          },
          "client_request_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "target_id",
          "operation",
          "value",
          "expected",
          "client_request_id"
        ],
        "additionalProperties": false,
        "allOf": [
          {
            "if": {
              "properties": {
                "operation": {
                  "const": "SET"
                }
              },
              "required": [
                "operation"
              ]
            },
            "then": {
              "properties": {
                "value": {
                  "type": "boolean"
                }
              }
            },
            "else": {
              "properties": {
                "value": {
                  "type": "null"
                }
              }
            }
          }
        ],
        "description": "Explicit foreground user intent only. Principal, role, installation authority, cause, execution_seq and MCU deadline are derived by Core, never trusted from client input. Expected snapshot is an observation, not an authority token."
      },
      "EffectEvidence": {
        "type": "object",
        "properties": {
          "status": {
            "enum": [
              "NOT_CHECKED",
              "OBSERVED",
              "INCONCLUSIVE",
              "MISMATCH"
            ]
          },
          "evidence_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "maxItems": 64
          },
          "explanation": {
            "type": "string",
            "maxLength": 2048
          }
        },
        "required": [
          "status",
          "evidence_ids",
          "explanation"
        ],
        "additionalProperties": false
      },
      "IntentRecord": {
        "type": "object",
        "properties": {
          "intent_id": {
            "type": "string",
            "format": "uuid"
          },
          "client_request_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "enum": [
              "RECEIVED",
              "REJECTED",
              "EXECUTED",
              "UNKNOWN"
            ]
          },
          "target_id": {
            "type": "string",
            "format": "uuid"
          },
          "operation": {
            "enum": [
              "SET",
              "RELEASE_MANUAL"
            ]
          },
          "value": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 256
          },
          "command_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "effect": {
            "$ref": "#/components/schemas/EffectEvidence"
          }
        },
        "required": [
          "intent_id",
          "client_request_id",
          "status",
          "target_id",
          "operation",
          "value",
          "created_at",
          "updated_at",
          "reason",
          "command_id",
          "effect"
        ],
        "additionalProperties": false,
        "description": "RECEIVED means durable acceptance only. EXECUTED requires authenticated MCU APPLIED evidence, not physical proof. UNKNOWN means a possible sent/applied action lacks conclusive result. REJECTED is pre-dispatch rejection or authenticated MCU rejection. UNKNOWN may later resolve; historical EXECUTED never gets rewritten from a newer snapshot."
      },
      "TargetState": {
        "type": "object",
        "properties": {
          "target_id": {
            "type": "string",
            "format": "uuid"
          },
          "node_boot_id": {
            "type": "string",
            "format": "uuid"
          },
          "controller_fence": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,19})$",
            "description": "Unsigned 64-bit decimal. Runtime must reject values >18446744073709551615; no JSON float conversion."
          },
          "manual_revision": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,19})$",
            "description": "Unsigned 64-bit decimal. Runtime must reject values >18446744073709551615; no JSON float conversion."
          },
          "output_revision": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,19})$",
            "description": "Unsigned 64-bit decimal. Runtime must reject values >18446744073709551615; no JSON float conversion."
          },
          "output": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "mode": {
            "enum": [
              "AUTO",
              "HOLD",
              "BOOT_INHIBIT",
              "UNKNOWN"
            ]
          },
          "freshness": {
            "enum": [
              "CURRENT",
              "STALE",
              "UNAVAILABLE"
            ]
          }
        },
        "required": [
          "target_id",
          "node_boot_id",
          "controller_fence",
          "manual_revision",
          "output_revision",
          "output",
          "mode",
          "freshness"
        ],
        "additionalProperties": false
      },
      "Snapshot": {
        "type": "object",
        "properties": {
          "snapshot_id": {
            "type": "string",
            "format": "uuid"
          },
          "installation_id": {
            "type": "string",
            "format": "uuid"
          },
          "cursor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          },
          "authorization_generation": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,19})$",
            "description": "Unsigned 64-bit decimal. Runtime must reject values >18446744073709551615; no JSON float conversion."
          },
          "targets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TargetState"
            },
            "maxItems": 4096
          }
        },
        "required": [
          "snapshot_id",
          "installation_id",
          "cursor",
          "authorization_generation",
          "targets"
        ],
        "additionalProperties": false,
        "description": "Coherent snapshot with an atomic event-log boundary. cursor is opaque, principal+installation+authorization-generation scoped. Client must not compare or construct it. New boot/state remain visible, but never retroactively rewrite a historical intent."
      },
      "Event": {
        "type": "object",
        "properties": {
          "cursor": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          },
          "kind": {
            "enum": [
              "TARGET_STATE",
              "INTENT_UPDATE",
              "AUTHORIZATION_CHANGED",
              "RESYNC_REQUIRED"
            ]
          },
          "snapshot_id": {
            "type": "string",
            "format": "uuid"
          },
          "authorization_generation": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,19})$",
            "description": "Unsigned 64-bit decimal. Runtime must reject values >18446744073709551615; no JSON float conversion."
          },
          "data": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/TargetState"
              },
              {
                "$ref": "#/components/schemas/IntentRecord"
              },
              {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 256
                  }
                },
                "required": [
                  "reason"
                ],
                "additionalProperties": false
              }
            ]
          }
        },
        "required": [
          "cursor",
          "kind",
          "snapshot_id",
          "authorization_generation",
          "data"
        ],
        "additionalProperties": false,
        "allOf": [
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "TARGET_STATE"
                }
              }
            },
            "then": {
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/TargetState"
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "INTENT_UPDATE"
                }
              }
            },
            "then": {
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/IntentRecord"
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "enum": [
                    "AUTHORIZATION_CHANGED",
                    "RESYNC_REQUIRED"
                  ]
                }
              }
            },
            "then": {
              "properties": {
                "data": {
                  "type": "object",
                  "properties": {
                    "reason": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 256
                    }
                  },
                  "required": [
                    "reason"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        ]
      }
    }
  },
  "x-evidence-status": "PROPOSED_DOCUMENT_ONLY",
  "x-runtime-gates": [
    "Session issuance/rotation/storage/revoke implementation",
    "Current ACL and generation checks before cache return and dispatch",
    "Durable idempotency/outbox/attempt record and crash injection",
    "Atomic snapshot/event cursor and bounded retention",
    "MCU result authentication and independent physical effect evidence"
  ]
}
