{
  "openapi": "3.1.0",
  "info": {
    "title": "cloacina-server API",
    "description": "REST API for the Cloacina workflow-orchestration server. WebSocket protocols (execution events, accumulator ingest, reactor commands, substrate delivery) are specified in the WebSocket Protocol reference of the documentation site.",
    "contact": {
      "name": "Dylan Storey",
      "email": "dylan.storey@gmail.com"
    },
    "license": {
      "name": "Apache-2.0",
      "url": "https://www.apache.org/licenses/LICENSE-2.0"
    },
    "version": "0.12.0"
  },
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "operational"
        ],
        "summary": "GET /health — liveness check (no auth, no DB)",
        "operationId": "health",
        "responses": {
          "200": {
            "description": "Server process is alive — `{\"status\": \"ok\"}`"
          }
        }
      }
    },
    "/ready": {
      "get": {
        "tags": [
          "operational"
        ],
        "summary": "GET /ready — readiness check, scoped to PLATFORM health only (DB\nreachable, embedded Python interpreter usable). CLOACI-T-0916:\ntenant-workload health is deliberately NOT part of readiness — one crashed\ncomputation graph used to flip `/ready` false on EVERY replica\nsimultaneously, letting a single bad package eject the whole server fleet\nfrom the load-balancer pool. Crashed graphs remain visible via\n`GET /v1/health/graphs` (state `stopped`/`crashed`) and metrics.",
        "description": "CLOACI-T-0919 adds one more PLATFORM predicate: a wedged Python runtime.\nThere is exactly one embedded CPython per process, so an uninterruptible\nmodule-scope hang disables Python package loading process-wide until\nrestart. That is this replica being broken — not a tenant workload\nmisbehaving — so it belongs in readiness, and it is replica-local (the\nwedge is set by THIS process's own import thread), which is precisely the\nproperty #231 required.",
        "operationId": "ready",
        "responses": {
          "200": {
            "description": "Ready — DB reachable and the embedded Python runtime is usable. Tenant-workload health (e.g. crashed computation graphs) does NOT affect readiness; see /v1/health/graphs."
          },
          "503": {
            "description": "Not ready — `reason` field explains (database unreachable, or the embedded Python runtime is wedged by a package import hang and this process must be restarted)"
          }
        }
      }
    },
    "/v1/agents": {
      "get": {
        "tags": [
          "fleet"
        ],
        "summary": "`GET /v1/agents` — operator-facing snapshot of the execution-agent fleet\nroster (admin only). CLOACI-I-0124 / WS-0b. CLOACI-T-0916: read from the\nDB-backed roster (heartbeat-recency-filtered), so the listing reflects the\nWHOLE fleet regardless of which replica each agent registered against.",
        "operationId": "list_agents",
        "responses": {
          "200": {
            "description": "Fleet roster",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_AgentInfo"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/auth/keys": {
      "get": {
        "tags": [
          "keys"
        ],
        "summary": "GET /auth/keys — list all API keys (no hashes or plaintext).\nRequires admin role.",
        "operationId": "list_keys",
        "responses": {
          "200": {
            "description": "All keys (no hashes or plaintext)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_KeyInfo"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "post": {
        "tags": [
          "keys"
        ],
        "summary": "POST /auth/keys — create a new API key.",
        "description": "Requires admin role. Non-admin keys cannot create keys with higher\npermissions than their own (prevents privilege escalation).\nReturns the plaintext key exactly once. It cannot be retrieved again.",
        "operationId": "create_key",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateKeyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Key created — plaintext returned exactly once",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeyCreatedResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/auth/keys/{key_id}": {
      "delete": {
        "tags": [
          "keys"
        ],
        "summary": "DELETE /auth/keys/:key_id — revoke an API key.\nRequires admin role within tenant (or god mode).",
        "operationId": "revoke_key",
        "parameters": [
          {
            "name": "key_id",
            "in": "path",
            "description": "Key UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Key revoked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeyRevokedResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid key ID format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Key not found or already revoked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/auth/local/login": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "`POST /v1/auth/local/login` — verify a password, mint a short-TTL key.",
        "operationId": "local_login",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LocalLoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Logged in — minted key returned once",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocalLoginResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid username or password",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "429": {
            "description": "Too many failed attempts — throttled; see Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/logout": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "`POST /v1/auth/logout` — revoke the caller's key + forget refresh state.",
        "operationId": "logout",
        "responses": {
          "200": {
            "description": "Logged out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogoutResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/auth/refresh": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "`POST /v1/auth/refresh` — silently re-mint the caller's short-TTL key.",
        "operationId": "refresh",
        "responses": {
          "200": {
            "description": "Re-minted key returned once",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocalLoginResponse"
                }
              }
            }
          },
          "400": {
            "description": "Key is not a refreshable login key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Invalid key, the account is disabled, or the login session has passed its absolute deadline",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "501": {
            "description": "Refresh for this provider not yet supported",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/auth/whoami": {
      "get": {
        "tags": [
          "auth"
        ],
        "summary": "`GET /v1/auth/whoami` — return the caller's tenant, role, and admin flag.\nAny authenticated key (read level); reads only the request's `AuthenticatedKey`.",
        "operationId": "whoami",
        "responses": {
          "200": {
            "description": "The caller's identity + role",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhoamiResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/auth/ws-ticket": {
      "post": {
        "tags": [
          "keys"
        ],
        "summary": "POST /auth/ws-ticket — exchange a Bearer token for a single-use WebSocket ticket.",
        "description": "Returns a short-lived ticket that can be used as a query parameter for\nWebSocket upgrade requests, avoiding long-lived API keys in URLs.",
        "operationId": "create_ws_ticket",
        "responses": {
          "200": {
            "description": "Single-use WebSocket ticket",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WsTicketResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/compiler/status": {
      "get": {
        "tags": [
          "compiler"
        ],
        "summary": "`GET /v1/compiler/status` — build-pipeline status (admin only).",
        "operationId": "compiler_status",
        "responses": {
          "200": {
            "description": "Build-pipeline status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompilerStatus"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/accumulators": {
      "get": {
        "tags": [
          "graph-health"
        ],
        "summary": "GET /v1/health/accumulators — list registered accumulators with health,\nfiltered by the caller's authorization. CLOACI-T-0579 / SEC-05.",
        "operationId": "list_accumulators",
        "responses": {
          "200": {
            "description": "Registered accumulators with health, filtered by authorization",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_AccumulatorStatus"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/accumulators/{name}/inject": {
      "post": {
        "tags": [
          "graph-health"
        ],
        "summary": "POST /v1/health/accumulators/{name}/inject — push a single typed event into\na running accumulator (CLOACI-T-0753).",
        "description": "Operator-facing REST analogue of the WS accumulator-push path. The typed JSON\n`event` is serialized to the boundary wire encoding server-side (same framing\nas the front-door accumulator socket), so operators never craft raw\n`Vec<u8>`. Authorization reuses the accumulator endpoint policy — the same\ngate the WS accumulator endpoint enforces. Successful injects are\naudit-logged and marked `operator_injected` since they bypass the real event\nsource.",
        "operationId": "inject_accumulator",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Accumulator name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InjectAccumulatorRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Event injected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InjectAccumulatorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid event payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Not authorized for this accumulator",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Accumulator not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/accumulators/{name}/interface": {
      "get": {
        "tags": [
          "graph-health"
        ],
        "summary": "GET /v1/health/accumulators/{name}/interface — the accumulator's declared\ninput interface (CLOACI-I-0128 T-0758): the single boundary slot an operator\nsupplies to `inject`. Empty `slots` means undeclared/untyped. Read-only\ndiscovery; the same slot backs the validation in `inject_accumulator`.",
        "operationId": "get_accumulator_interface",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Accumulator name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Declared accumulator input interface",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeclaredSurface"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/graphs": {
      "get": {
        "tags": [
          "graph-health"
        ],
        "summary": "GET /v1/health/graphs — list loaded graphs visible to the caller.\nCLOACI-T-0579 / SEC-05.",
        "operationId": "list_graphs",
        "responses": {
          "200": {
            "description": "Loaded graphs visible to the caller",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_GraphStatus"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/graphs/{name}": {
      "get": {
        "tags": [
          "graph-health"
        ],
        "summary": "GET /v1/health/graphs/{name} — single graph health, gated by caller\nauthorization. Cross-tenant requests 404 rather than 403 so an\nadversary can't probe for tenant graph names. CLOACI-T-0579.",
        "operationId": "get_graph",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Graph name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Single graph health",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GraphStatus"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Graph not found (or not visible to caller)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/reactors": {
      "get": {
        "tags": [
          "graph-health"
        ],
        "summary": "GET /v1/health/reactors — list loaded reactors visible to the caller\n(CLOACI-T-0742). Reactor-first: includes reactors with no graph bound, which\n`list_graphs` omits. Visibility reuses the same tenant gate as graphs.",
        "operationId": "list_reactors",
        "responses": {
          "200": {
            "description": "Loaded reactors visible to the caller",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_ReactorStatus"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/reactors/{name}/fire": {
      "post": {
        "tags": [
          "graph-health"
        ],
        "summary": "POST /v1/health/reactors/{name}/fire — manually fire a running reactor\n(CLOACI-T-0751).",
        "description": "Operator-facing REST surface over the existing reactor `ForceFire` /\n`FireWith` mechanics (previously WebSocket-only). Two modes:\n\n- `force_fire`: fire the graph with the reactor's current cache, untouched.\n- `fire_with`: replace the reactor's cache with the supplied typed `inputs`\n  then fire. Full-replace only (mirrors the engine's `replace_all`); there\n  is no partial/merge mode in v1.\n\nTyped JSON `inputs` are serialized to the boundary wire encoding\nserver-side so operators never deal in raw `Vec<u8>`. Each source value is\nencoded exactly as the front-door accumulator path encodes it: the JSON is\nrendered to UTF-8 bytes, then those bytes are bincode-wrapped\n(`bincode(Vec<u8>)`) — the format the passthrough accumulator and the FFI\nbridge expect.\n\nAuthorization reuses the existing per-op reactor policy\n(`ReactorOp::ForceFire` / `ReactorOp::FireWith`), the same gate the WS\nreactor endpoint enforces. Successful fires are audit-logged and marked\n`operator_injected` since they bypass the real event source.",
        "operationId": "fire_reactor",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Reactor name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FireReactorRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Reactor fired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FireReactorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Operation not permitted on this reactor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Reactor not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/reactors/{name}/fires": {
      "get": {
        "tags": [
          "graph-health"
        ],
        "summary": "GET /v1/health/reactors/{name}/fires — recent fires with outcome + duration\n(CLOACI-T-0766). Makes the reactive layer observable: what fired, did it\ncomplete, how long, and why it failed.",
        "operationId": "list_reactor_fires",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Reactor name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recent fires, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_ReactorFire"
                }
              }
            }
          },
          "404": {
            "description": "Reactor not found / not visible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/reactors/{name}/fires/timeseries": {
      "get": {
        "tags": [
          "graph-health"
        ],
        "summary": "GET /v1/health/reactors/{name}/fires/timeseries — fires per minute, last 60\nminutes (CLOACI-T-0766), for the fire-activity heatmap.",
        "operationId": "reactor_fire_timeseries",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Reactor name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-minute fire counts (oldest first)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReactorFireTimeseries"
                }
              }
            }
          },
          "404": {
            "description": "Reactor not found / not visible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/health/reactors/{name}/interface": {
      "get": {
        "tags": [
          "graph-health"
        ],
        "summary": "GET /v1/health/reactors/{name}/interface — the reactor's declared input\ninterface (CLOACI-I-0128 T-0758): the per-source boundary slots an operator\nsupplies to `fire_with`. Empty `slots` means undeclared/untyped (the reactor\naccepts free-form input). Read-only discovery so a UI can render a typed fire\nform; the same slots back the server-side validation in `fire_reactor`.",
        "operationId": "get_reactor_interface",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "description": "Reactor name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Declared reactor input interface",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeclaredSurface"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants": {
      "get": {
        "tags": [
          "tenants"
        ],
        "summary": "GET /tenants — list tenant schemas.\nRequires admin role — only admins can enumerate tenants.",
        "operationId": "list_tenants",
        "responses": {
          "200": {
            "description": "Tenant schemas",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_TenantSummary"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin (god-mode) key required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "post": {
        "tags": [
          "tenants"
        ],
        "summary": "POST /tenants — create a new tenant (Postgres schema + user + migrations).\nAdmin-only: only is_admin keys can create tenants.",
        "operationId": "create_tenant",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTenantRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Tenant created (credentials intentionally excluded)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantCreatedResponse"
                }
              }
            }
          },
          "400": {
            "description": "Tenant creation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin (god-mode) key required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{schema_name}": {
      "delete": {
        "tags": [
          "tenants"
        ],
        "summary": "DELETE /tenants/:schema_name — remove a tenant via orchestrated teardown.",
        "description": "CLOACI-T-0581: replaces the old single-call `admin.remove_tenant` with\nthe four-step top-down order:\n  1. Revoke every still-active API key for the tenant (close the auth\n     surface so new requests fail).\n  2. Evict the tenant's `DefaultRunner` from `TenantRunnerCache`,\n     awaiting its graceful shutdown (drains in-flight executions,\n     stops scheduler loop, closes per-tenant DB pool).\n  3. Evict the tenant's `Database` from `TenantDatabaseCache`.\n  4. Drop schema + user via `DatabaseAdmin::remove_tenant`.\n\nEach step emits a structured audit event with duration. Per-step\nfailures bail out — but earlier steps stay committed, so a retry\npicks up where the failure occurred. Each step is idempotent.\n\nCloses SEC-14 (stale state after delete) and SEC-17 (unbounded\ncaches surviving delete).",
        "operationId": "remove_tenant",
        "parameters": [
          {
            "name": "schema_name",
            "in": "path",
            "description": "Tenant schema name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant removed — teardown report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantRemovedResponse"
                }
              }
            }
          },
          "400": {
            "description": "Tenant removal failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin (god-mode) key required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Teardown step failed (safe to retry)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/accounts": {
      "get": {
        "tags": [
          "auth"
        ],
        "summary": "`GET /v1/tenants/{tenant_id}/accounts` — list a tenant's local accounts.",
        "operationId": "list_accounts",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant local accounts (no hashes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_AccountInfo"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "`POST /v1/tenants/{tenant_id}/accounts` — create a tenant local account.",
        "operationId": "create_account",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAccountRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Account created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountInfo"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/accounts/{account_id}": {
      "delete": {
        "tags": [
          "auth"
        ],
        "summary": "`DELETE /v1/tenants/{tenant_id}/accounts/{account_id}` — disable an account.\nDisable (not hard-delete) preserves history; already-minted keys lapse at\ntheir TTL (deprovisioning latency bounded by the short TTL).",
        "operationId": "disable_account",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "account_id",
            "in": "path",
            "description": "Account UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Account disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountActionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Account not found in this tenant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/accounts/{account_id}/password": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "`POST /v1/tenants/{tenant_id}/accounts/{account_id}/password` — admin reset.",
        "operationId": "reset_password",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "account_id",
            "in": "path",
            "description": "Account UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetPasswordRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Password reset",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountActionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Account not found in this tenant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/executions": {
      "get": {
        "tags": [
          "executions"
        ],
        "summary": "GET /tenants/:tenant_id/executions — list workflow executions.",
        "description": "**CLOACI-T-0594 / API-02:** accepts `?status=Failed` and\n`?workflow_name=foo` and `?limit=N&offset=M`. Previously these\nquery params were silently discarded.",
        "operationId": "list_executions",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "workflow",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Executions page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantListResponse_ExecutionSummary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid pagination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/executions/{exec_id}": {
      "get": {
        "tags": [
          "executions"
        ],
        "summary": "GET /tenants/:tenant_id/executions/:id — get execution details.",
        "operationId": "get_execution",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "exec_id",
            "in": "path",
            "description": "Execution UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Execution detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExecutionDetail"
                }
              }
            }
          },
          "400": {
            "description": "Invalid execution ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Execution not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/executions/{exec_id}/events": {
      "get": {
        "tags": [
          "executions"
        ],
        "summary": "GET /tenants/:tenant_id/executions/:id/events — execution event log.",
        "operationId": "get_execution_events",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "exec_id",
            "in": "path",
            "description": "Execution UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Execution event log",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExecutionEventsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid execution ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/executions/{exec_id}/tasks": {
      "get": {
        "tags": [
          "executions"
        ],
        "summary": "GET /tenants/:tenant_id/executions/:id/tasks — per-task rows for an execution.",
        "operationId": "get_execution_tasks",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "exec_id",
            "in": "path",
            "description": "Execution UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-task execution rows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExecutionTasksResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid execution ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/keys": {
      "get": {
        "tags": [
          "keys"
        ],
        "summary": "GET /tenants/:tenant_id/keys — list keys scoped to one tenant (CLOACI-T-0784).\nTenant-admin self-service; authZ (`TenantParam + Admin`) is enforced by the\nroute-table middleware, so the caller is already confined to `tenant_id`.",
        "operationId": "list_tenant_keys",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant keys (no hashes or plaintext)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_KeyInfo"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "post": {
        "tags": [
          "keys"
        ],
        "summary": "POST /tenants/:tenant_id/keys — create a key scoped to a tenant.\nAdmin-only: only is_admin keys can create tenant-scoped keys.",
        "operationId": "create_tenant_key",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateKeyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Tenant-scoped key created — plaintext returned exactly once",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeyCreatedResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Admin (god-mode) key required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/keys/{key_id}": {
      "delete": {
        "tags": [
          "keys"
        ],
        "summary": "DELETE /tenants/:tenant_id/keys/:key_id — revoke a key owned by one tenant\n(CLOACI-T-0784). The middleware confines the caller to `tenant_id`; this\nhandler additionally verifies the target key belongs to that tenant before\nrevoking. A cross-tenant or unknown id is reported as not-found (never\nrevoked) so a tenant-admin can't probe or touch another tenant's keys.",
        "operationId": "revoke_tenant_key",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "key_id",
            "in": "path",
            "description": "Key UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Key revoked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeyRevokedResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid key ID format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Key not found in this tenant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/secrets": {
      "get": {
        "tags": [
          "secrets"
        ],
        "summary": "`GET /v1/tenants/{tenant_id}/secrets` — list secret metadata. **No values.**",
        "operationId": "list_secrets",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Secret metadata (names + timestamps only)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse_SecretMetadataResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "503": {
            "description": "Secrets not configured on this server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "post": {
        "tags": [
          "secrets"
        ],
        "summary": "`POST /v1/tenants/{tenant_id}/secrets` — create a secret from a field map.\nReturns metadata only.",
        "operationId": "create_secret",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSecretRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Secret created — metadata only (no values)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecretMetadataResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "409": {
            "description": "A secret of that name already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "503": {
            "description": "Secrets not configured on this server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/secrets/{name}": {
      "get": {
        "tags": [
          "secrets"
        ],
        "summary": "`GET /v1/tenants/{tenant_id}/secrets/{name}` — one secret's metadata. **No values.**",
        "operationId": "get_secret",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Secret name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Secret metadata (names + timestamps only)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecretMetadataResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Secret not found in this tenant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "503": {
            "description": "Secrets not configured on this server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "put": {
        "tags": [
          "secrets"
        ],
        "summary": "`PUT /v1/tenants/{tenant_id}/secrets/{name}` — rotate a secret's values in\nplace (D-8/OQ-5). Returns metadata only; the next fire sees the new value.",
        "operationId": "rotate_secret",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Secret name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RotateSecretRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Secret rotated — metadata only (no values)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecretMetadataResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Secret not found in this tenant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "503": {
            "description": "Secrets not configured on this server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "delete": {
        "tags": [
          "secrets"
        ],
        "summary": "`DELETE /v1/tenants/{tenant_id}/secrets/{name}` — delete a secret.",
        "operationId": "delete_secret",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Secret name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Secret deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecretDeletedResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or admin role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Secret not found in this tenant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "503": {
            "description": "Secrets not configured on this server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/triggers": {
      "get": {
        "tags": [
          "triggers"
        ],
        "summary": "GET /tenants/:tenant_id/triggers — list all schedules (cron + trigger).",
        "description": "CLOACI-T-0579: routed through the tenant-scoped `Database` from\n`TenantDatabaseCache` so the underlying `SELECT FROM schedules`\nhits the tenant's schema, not the admin schema. Closes SEC-02.",
        "operationId": "list_triggers",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schedules page (cron + trigger)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantListResponse_TriggerScheduleSummary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid pagination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/triggers/{name}": {
      "get": {
        "tags": [
          "triggers"
        ],
        "summary": "GET /tenants/:tenant_id/triggers/:name — trigger details + recent executions.",
        "description": "CLOACI-T-0579: routed through the tenant-scoped `Database`. A request\nfor tenant B with a trigger id that belongs to tenant A naturally\n404s — the row simply doesn't exist in tenant B's schema. No\ninfo-disclosure via \"not in your tenant\" error code. Closes SEC-02.",
        "operationId": "get_trigger",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Trigger or workflow name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trigger detail + recent executions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TriggerDetailResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Trigger not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/triggers/{name}/fire": {
      "post": {
        "tags": [
          "triggers"
        ],
        "summary": "POST /tenants/:tenant_id/triggers/:name/fire — manually fire a trigger,\nfanning out to every subscribed workflow (CLOACI-T-0777). One operator action\ninstead of running each workflow by hand. An optional `event` is merged into\neach fired workflow's context (alongside trigger metadata). The started\nexecutions are marked `manual` (CLOACI-T-0776).",
        "operationId": "fire_trigger",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Trigger name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FireTriggerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Trigger fired; fan-out result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FireTriggerResponse"
                }
              }
            }
          },
          "400": {
            "description": "Event does not match the trigger's declared pass-through schema",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "The trigger drives no workflow: no `on = ..` schedule and no subscriber",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/triggers/{name}/interface": {
      "get": {
        "tags": [
          "triggers"
        ],
        "summary": "GET /tenants/:tenant_id/triggers/:name/interface — the trigger's declared\npass-through schema (CLOACI-T-0777 P2): the union of the declared params of\nevery workflow subscribed to this trigger. Empty `slots` means an untyped\ntrigger (free-form event). Read-only discovery; the same slots back the\nvalidation in `fire_trigger`, and the UI builds a typed fire form from them.",
        "operationId": "get_trigger_interface",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Trigger name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trigger pass-through interface",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeclaredSurface"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/triggers/{name}/pause": {
      "post": {
        "tags": [
          "triggers"
        ],
        "summary": "POST /tenants/:tenant_id/triggers/:name/pause — pause a schedule (CLOACI-T-0749).",
        "description": "Resolves the schedule by trigger name or workflow name (same as\n`get_trigger`) and sets it paused so the scheduler stops firing it. Works\nfor both `trigger` and `cron` schedules. In-flight executions are\nunaffected; this only gates new ones.",
        "operationId": "pause_trigger",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Trigger or workflow name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schedule paused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TriggerPauseResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Trigger not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/triggers/{name}/resume": {
      "post": {
        "tags": [
          "triggers"
        ],
        "summary": "POST /tenants/:tenant_id/triggers/:name/resume — resume a paused schedule\n(CLOACI-T-0749). Re-arms on the normal schedule; missed fires are not\ncaught up (skip policy).",
        "operationId": "resume_trigger",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Trigger or workflow name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Schedule resumed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TriggerPauseResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Trigger not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows": {
      "get": {
        "tags": [
          "workflows"
        ],
        "summary": "GET /tenants/:tenant_id/workflows — list registered workflows.",
        "operationId": "list_workflows",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Registered workflows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantListResponse_WorkflowSummary"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "post": {
        "tags": [
          "workflows"
        ],
        "summary": "POST /tenants/:tenant_id/workflows — multipart upload of .cloacina source package.",
        "operationId": "upload_workflow",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "The first file field is taken as the .cloacina package",
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PackageUploadForm"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Package registered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowUploadedResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or empty package",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant/role denied or signature verification failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows/{name}": {
      "get": {
        "tags": [
          "workflows"
        ],
        "summary": "GET /tenants/:tenant_id/workflows/:name — get workflow details.",
        "operationId": "get_workflow",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Package name, or package UUID to inspect pending/building/failed rows",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Workflow detail incl. build state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDetail"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Workflow not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows/{name}/execute": {
      "post": {
        "tags": [
          "executions"
        ],
        "summary": "POST /tenants/:tenant_id/workflows/:name/execute — execute a workflow.",
        "description": "CLOACI-T-0580: execution is routed through `TenantRunnerCache`, which\nreturns (or constructs) a `DefaultRunner` bound to the tenant's\n`Database`. The execution row + every event lands in the tenant's\nschema, never the admin schema.",
        "operationId": "execute_workflow",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Workflow name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExecuteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Execution scheduled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExecuteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Execution failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Workflow not registered for this tenant (I-0138 cross-tenant gate; `public` is exempt)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows/{name}/instances": {
      "get": {
        "tags": [
          "instances"
        ],
        "summary": "GET /tenants/:tenant_id/workflows/:name/instances — list a workflow's named\ninstances.",
        "description": "Anonymous schedules (cron rows with no `instance_name`) are excluded — this\nendpoint is about named bindings, and the trigger endpoints already cover\nthe general schedule listing.",
        "operationId": "list_instances",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Workflow name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Instances for this workflow",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantListResponse_WorkflowInstanceSummary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid pagination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "post": {
        "tags": [
          "instances"
        ],
        "summary": "POST /tenants/:tenant_id/workflows/:name/instances — create a named instance.",
        "description": "Params are validated against the workflow's declared `params(...)` slots\nusing the same `validate_declared_params` the execute route uses, so a\nscheduled instance cannot be created with a binding that would fail at every\nfire — the failure surfaces at creation time instead of silently at 3am.\n\n`cron` is optional. Without it the instance is created **unscheduled**: a\ndurable named param binding with `next_run_at = NULL`, which the scheduler's\ndue-query can never select (`NULL <= now` is never true).",
        "operationId": "create_instance",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Workflow name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInstanceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Instance created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowInstanceSummary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid params, cron expression, or timezone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "409": {
            "description": "Instance name already exists for this workflow",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows/{name}/instances/{instance}": {
      "get": {
        "tags": [
          "instances"
        ],
        "summary": "GET /tenants/:tenant_id/workflows/:name/instances/:instance — one instance.",
        "operationId": "get_instance",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Workflow name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "instance",
            "in": "path",
            "description": "Instance name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Instance detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowInstanceSummary"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Instance not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
      "delete": {
        "tags": [
          "instances"
        ],
        "summary": "DELETE /tenants/:tenant_id/workflows/:name/instances/:instance — remove a\nnamed instance.",
        "description": "Deletes the binding and its schedule. In-flight executions already started\nby this instance are unaffected; only future fires are prevented.",
        "operationId": "delete_instance",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Workflow name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "instance",
            "in": "path",
            "description": "Instance name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Instance deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteInstanceResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Instance not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows/{name}/pause": {
      "post": {
        "tags": [
          "workflows"
        ],
        "summary": "POST /tenants/:tenant_id/workflows/:name/pause — pause a workflow (CLOACI-T-0749).",
        "description": "Blocks new executions of the workflow (manual and triggered) until resumed.\nIn-flight executions are unaffected. `name` may be the workflow name or\npackage name.",
        "operationId": "pause_workflow",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Workflow or package name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Workflow paused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowPauseResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Workflow not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows/{name}/resume": {
      "post": {
        "tags": [
          "workflows"
        ],
        "summary": "POST /tenants/:tenant_id/workflows/:name/resume — resume a paused workflow\n(CLOACI-T-0749). New executions are accepted again.",
        "operationId": "resume_workflow",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Workflow or package name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Workflow resumed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowPauseResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Workflow not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows/{name}/source": {
      "get": {
        "tags": [
          "workflows"
        ],
        "summary": "GET /tenants/:tenant_id/workflows/:name/source — read-only source view.",
        "description": "Surfaces the original source retained in the package's `.cloacina` archive\n(CLOACI-T-0750). `name` may be a package name or a package UUID, matching\n`get_workflow`. Source is independent of build state, so it is available\neven while a package is building or after a failed build.",
        "operationId": "get_workflow_source",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Package name, or package UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Workflow source files",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowSourceResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Workflow not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    },
    "/v1/tenants/{tenant_id}/workflows/{name}/{version}": {
      "delete": {
        "tags": [
          "workflows"
        ],
        "summary": "DELETE /tenants/:tenant_id/workflows/:name/:version — unregister workflow.",
        "operationId": "delete_workflow",
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "description": "Tenant identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "path",
            "description": "Package name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "description": "Package version",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Workflow unregistered. Idempotent: also returned when no matching package existed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDeletedResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "403": {
            "description": "Tenant access or role denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Registry lookup failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AccountActionResponse": {
        "type": "object",
        "description": "Outcome of a disable/reset action.",
        "required": [
          "status",
          "id"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "AccountInfo": {
        "type": "object",
        "description": "Public view of a local account (never the password hash).",
        "required": [
          "id",
          "username",
          "role",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "username": {
            "type": "string"
          }
        }
      },
      "AccumulatorStatus": {
        "type": "object",
        "description": "One row in `GET /v1/health/accumulators`.",
        "required": [
          "name",
          "status"
        ],
        "properties": {
          "buffer_capacity": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Declared buffer capacity for bounded kinds — state `capacity = N`, batch\n`max_buffer_size`. `None` when unbounded or not applicable. The UI\nrenders `buffer_depth/buffer_capacity` as fill (CLOACI-T-0744).",
            "minimum": 0
          },
          "buffer_depth": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Buffered-event count for buffering kinds — batch (events awaiting flush)\nand state (window entries). `None` for kinds that don't buffer\n(passthrough/stream/polling) or runtimes predating the gauge\n(CLOACI-T-0744).",
            "minimum": 0
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Degradation detail when the source is unhealthy (e.g. connection error)."
          },
          "events_total": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Total boundaries emitted since load (monotonic). `None` when untracked.",
            "minimum": 0
          },
          "last_event_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "Wall-clock of the last boundary this accumulator emitted (RFC3339), or\n`None` if it hasn't emitted yet / the runtime predates freshness tracking."
          },
          "last_operator_inject_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 time of the last operator inject, or `None` if never\n(CLOACI-T-0776)."
          },
          "name": {
            "type": "string"
          },
          "operator_injects": {
            "type": "integer",
            "format": "int64",
            "description": "Number of operator injects into this accumulator since load\n(CLOACI-T-0776) — manual interventions via the REST/WS inject paths. `0`\nwhen never injected. The UI marks injected accumulators with a \"manual\" pill.",
            "minimum": 0
          },
          "reactor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The reactor (graph) this accumulator feeds, self-registered by the graph\nat load (CLOACI-I-0128 follow-up). `None` for older runtimes that didn't\nregister the descriptor. Lets an operator see what pushing to\n`/v1/ws/accumulator/{name}` actually drives."
          },
          "state": {
            "type": [
              "string",
              "null"
            ],
            "description": "Health state label (`live`/`socket_only`/`disconnected`/…), CLOACI-T-0765.\nMirrors the `state` inside `status`; promoted to a typed field for the UI."
          },
          "status": {
            "description": "Accumulator health as reported by the endpoint registry. Free-form\nJSON for now; structured in a later contract revision."
          },
          "tenant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Owning tenant, or `None` for untagged single-tenant graphs."
          }
        }
      },
      "AgentInfo": {
        "type": "object",
        "description": "One registered execution agent in the in-memory fleet roster.",
        "required": [
          "agent_id",
          "target_triple",
          "max_concurrency",
          "in_flight",
          "available_capacity",
          "seconds_since_heartbeat",
          "capabilities"
        ],
        "properties": {
          "agent_id": {
            "type": "string"
          },
          "available_capacity": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "in_flight": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "max_concurrency": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "seconds_since_heartbeat": {
            "type": "integer",
            "format": "int64",
            "description": "Seconds since this agent's last heartbeat — the liveness signal an\noperator reads (the underlying record stores a monotonic `Instant`,\nnot a wall-clock time).",
            "minimum": 0
          },
          "target_triple": {
            "type": "string"
          },
          "tenant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tenant scope the agent registered under, if any."
          }
        }
      },
      "CompilerStatus": {
        "type": "object",
        "description": "Build-pipeline state, derived from the build queue in the database — the\nsame rows the compiler's own `/v1/status` reports. The server reads them\ndirectly, so this needs no HTTP coupling to the compiler service.",
        "required": [
          "status",
          "pending",
          "building"
        ],
        "properties": {
          "building": {
            "type": "integer",
            "format": "int64",
            "description": "Packages currently building.",
            "minimum": 0
          },
          "last_failure_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp of the most recent failed build, if any."
          },
          "last_success_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp of the most recent successful build, if any."
          },
          "pending": {
            "type": "integer",
            "format": "int64",
            "description": "Packages awaiting compilation.",
            "minimum": 0
          },
          "seconds_since_heartbeat": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Seconds since the compiler last claimed a build (its DB-visible\nheartbeat). Only meaningful while a build is in flight.",
            "minimum": 0
          },
          "status": {
            "type": "string",
            "description": "Coarse roll-up: `\"building\"` (work in flight), `\"backlogged\"` (packages\npending but none building — the compiler may be down), or `\"idle\"`\n(nothing queued; liveness is undeterminable from the queue alone)."
          }
        }
      },
      "CreateAccountRequest": {
        "type": "object",
        "description": "Create a local account in a tenant.",
        "required": [
          "username",
          "password",
          "role"
        ],
        "properties": {
          "password": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "username": {
            "type": "string"
          }
        }
      },
      "CreateInstanceRequest": {
        "type": "object",
        "description": "Body for `POST /tenants/{tenant_id}/workflows/{name}/instances`.",
        "required": [
          "instance_name"
        ],
        "properties": {
          "cron": {
            "type": [
              "string",
              "null"
            ],
            "description": "Cron expression. When omitted the instance is created **unscheduled** —\na durable named param binding that never fires on its own."
          },
          "enabled": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether the schedule is enabled on creation. Defaults to `true`."
          },
          "instance_name": {
            "type": "string",
            "description": "Instance name, unique per `(workflow_name, instance_name)` within the\ntenant."
          },
          "params": {
            "description": "Parameter values bound to this instance, validated against the\nworkflow's declared `params(...)` slots."
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ],
            "description": "IANA timezone for `cron`. Defaults to `UTC`."
          }
        }
      },
      "CreateKeyRequest": {
        "type": "object",
        "description": "Request body for `POST /auth/keys` and `POST /tenants/{tenant_id}/keys`.",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/KeyRole"
          }
        }
      },
      "CreateSecretRequest": {
        "type": "object",
        "description": "Request body for `POST /v1/tenants/{tenant_id}/secrets` — create a secret.\n\n`fields` is the `{field_name: value}` map. The values are write-only: they\nare encrypted at rest and never returned by any read endpoint.",
        "required": [
          "name",
          "fields"
        ],
        "properties": {
          "fields": {
            "type": "object",
            "description": "The `{field: value}` map. Values are write-only.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "name": {
            "type": "string",
            "description": "The secret's name (unique within the tenant)."
          }
        }
      },
      "CreateTenantRequest": {
        "type": "object",
        "description": "Request body for `POST /tenants`.",
        "required": [
          "name"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional operator-facing description."
          },
          "name": {
            "type": "string",
            "description": "Tenant name — doubles as schema name + database username.\nMust be alphanumeric + underscore."
          },
          "password": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional password (auto-generated if absent)."
          }
        }
      },
      "DeclaredSurface": {
        "type": "object",
        "description": "A declared injectable surface other than the workflow itself — a computation\ngraph, reactor, or accumulator (CLOACI-I-0128 Task D). Carries the surface's\ndeclared input slots so the server can validate operator injections\n(reactor fire / accumulator inject) and the UI can render typed forms.\n\nSourced from the package's `get_input_interface` FFI entrypoint at build\nsuccess and stored alongside the package metadata. An undeclared / untyped\nsurface has `slots` whose schemas are permissive (`{}`).",
        "required": [
          "kind",
          "name",
          "slots"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "description": "Surface kind: `\"graph\"`, `\"reactor\"`, or `\"accumulator\"`."
          },
          "name": {
            "type": "string",
            "description": "Surface name (graph name / reactor name / accumulator name)."
          },
          "slots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InputSlot"
            },
            "description": "The surface's declared input slots."
          }
        }
      },
      "DeleteInstanceResponse": {
        "type": "object",
        "description": "Response for a delete.",
        "required": [
          "tenant_id",
          "workflow_name",
          "instance_name",
          "deleted"
        ],
        "properties": {
          "deleted": {
            "type": "boolean"
          },
          "instance_name": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string"
          },
          "workflow_name": {
            "type": "string"
          }
        }
      },
      "ErrorBody": {
        "type": "object",
        "description": "Standardized error response body. Every non-2xx response from\n`cloacina-server` carries this shape; the request correlation ID is in\nthe `x-request-id` response header, not the body.",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code (e.g. `invalid_pagination`,\n`workflow_not_found`)."
          },
          "error": {
            "type": "string",
            "description": "Human-readable error message."
          }
        }
      },
      "ExecuteRequest": {
        "type": "object",
        "description": "Request body for `POST /tenants/{tenant_id}/workflows/{name}/execute`.",
        "properties": {
          "context": {
            "description": "Optional JSON context to pass to the workflow."
          }
        }
      },
      "ExecuteResponse": {
        "type": "object",
        "description": "`202 Accepted` body for a scheduled workflow execution.",
        "required": [
          "execution_id",
          "workflow_name",
          "tenant_id",
          "status"
        ],
        "properties": {
          "execution_id": {
            "type": "string",
            "description": "UUID of the scheduled execution."
          },
          "status": {
            "type": "string",
            "description": "Always `\"scheduled\"` at accept time."
          },
          "tenant_id": {
            "type": "string"
          },
          "workflow_name": {
            "type": "string"
          }
        }
      },
      "ExecutionDetail": {
        "type": "object",
        "description": "`GET /tenants/{tenant_id}/executions/{id}` response.",
        "required": [
          "tenant_id",
          "execution_id",
          "status"
        ],
        "properties": {
          "execution_id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string"
          }
        }
      },
      "ExecutionEvent": {
        "type": "object",
        "description": "One row in the execution event log.",
        "required": [
          "id",
          "event_type",
          "created_at",
          "sequence_num"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "event_data": {
            "type": [
              "string",
              "null"
            ],
            "description": "JSON-encoded additional data for the event; `null` when absent."
          },
          "event_type": {
            "type": "string"
          },
          "id": {
            "type": "string",
            "description": "Event UUID."
          },
          "sequence_num": {
            "type": "integer",
            "format": "int64"
          },
          "task_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Local name of the task this event is about, resolved from the event's\n`task_execution_id`. `null` for workflow-scoped events (e.g.\n`workflow_completed`) or when the task can't be resolved\n(CLOACI-I-0124 / WS-9)."
          }
        }
      },
      "ExecutionEventsResponse": {
        "type": "object",
        "description": "`GET /tenants/{tenant_id}/executions/{id}/events` response.",
        "required": [
          "tenant_id",
          "execution_id",
          "events"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExecutionEvent"
            }
          },
          "execution_id": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string"
          }
        }
      },
      "ExecutionSummary": {
        "type": "object",
        "description": "One row in the executions list.",
        "required": [
          "id",
          "workflow_name",
          "status",
          "started_at"
        ],
        "properties": {
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp; `null` while still running."
          },
          "id": {
            "type": "string",
            "description": "Execution UUID."
          },
          "started_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "status": {
            "type": "string"
          },
          "trigger_origin": {
            "type": [
              "string",
              "null"
            ],
            "description": "How the run was triggered (CLOACI-T-0776): `\"manual\"` for an operator run\nvia the REST execute endpoint; `null` for cron/trigger/reactor-driven runs.\nThe UI marks manual runs with a \"manual\" pill."
          },
          "workflow_name": {
            "type": "string"
          }
        }
      },
      "ExecutionTasksResponse": {
        "type": "object",
        "description": "`GET /tenants/{tenant_id}/executions/{id}/tasks` response.",
        "required": [
          "tenant_id",
          "execution_id",
          "tasks"
        ],
        "properties": {
          "execution_id": {
            "type": "string"
          },
          "tasks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskExecutionDetail"
            }
          },
          "tenant_id": {
            "type": "string"
          }
        }
      },
      "FireMode": {
        "type": "string",
        "description": "How a manual REST fire should populate the reactor's input cache.\n\nCLOACI-T-0751. Mirrors the two WS write commands (`ForceFire` /\n`FireWith`) but with operator-friendly, typed input.",
        "enum": [
          "force_fire",
          "fire_with"
        ]
      },
      "FireReactorRequest": {
        "type": "object",
        "description": "Request body for `POST /v1/health/reactors/{name}/fire` (CLOACI-T-0751).\n\nOperators supply typed JSON per source; the server serializes each value\nto the boundary wire encoding so callers never deal in raw `Vec<u8>`.",
        "properties": {
          "inputs": {
            "type": "object",
            "description": "Per-source typed payloads, keyed by accumulator source name. Each\nJSON value is serialized to the boundary encoding server-side.\nRequired (and non-empty) when `mode` is `fire_with`; ignored for\n`force_fire`. Each value may be any JSON.",
            "additionalProperties": {},
            "propertyNames": {
              "type": "string"
            }
          },
          "mode": {
            "$ref": "#/components/schemas/FireMode",
            "description": "Whether to fire with the current cache (`force_fire`) or to inject\n`inputs` first (`fire_with`). Defaults to `force_fire`."
          }
        }
      },
      "FireReactorResponse": {
        "type": "object",
        "description": "Response body for a successful manual reactor fire (CLOACI-T-0751).",
        "required": [
          "reactor",
          "mode",
          "sources_injected"
        ],
        "properties": {
          "mode": {
            "$ref": "#/components/schemas/FireMode",
            "description": "The mode that was applied."
          },
          "reactor": {
            "type": "string",
            "description": "Echoes the reactor name that was fired."
          },
          "sources_injected": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Source names whose values were injected (empty for `force_fire`)."
          }
        }
      },
      "FireTriggerRequest": {
        "type": "object",
        "description": "`POST /tenants/{tenant_id}/triggers/{name}/fire` request (CLOACI-T-0777).\nManually push an event to a trigger; it fans out to every subscribed workflow.",
        "properties": {
          "event": {
            "description": "Optional typed event merged into each fired workflow's context, validated\nagainst the trigger's declared params (CLOACI-T-0777 P2). Omit to fire with\njust the trigger metadata."
          }
        }
      },
      "FireTriggerResponse": {
        "type": "object",
        "description": "`POST /tenants/{tenant_id}/triggers/{name}/fire` response (CLOACI-T-0777).",
        "required": [
          "tenant_id",
          "trigger",
          "fired",
          "executions"
        ],
        "properties": {
          "executions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FiredExecution"
            },
            "description": "The started executions: `(workflow_name, execution_id)`."
          },
          "fired": {
            "type": "integer",
            "format": "int32",
            "description": "How many workflows were fired (the fan-out count): the `on = ..`\nworkflow of the trigger plus its subscribers, each once.",
            "minimum": 0
          },
          "tenant_id": {
            "type": "string"
          },
          "trigger": {
            "type": "string",
            "description": "The trigger name fired."
          }
        }
      },
      "FiredExecution": {
        "type": "object",
        "description": "One workflow fired by a manual trigger fire (CLOACI-T-0777).",
        "required": [
          "workflow_name",
          "execution_id"
        ],
        "properties": {
          "execution_id": {
            "type": "string"
          },
          "workflow_name": {
            "type": "string"
          }
        }
      },
      "GraphStatus": {
        "type": "object",
        "description": "One row in `GET /v1/health/graphs`, and the `GET /v1/health/graphs/{name}`\nresponse body.",
        "required": [
          "name",
          "health",
          "accumulators",
          "paused"
        ],
        "properties": {
          "accumulators": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of the accumulators feeding this graph."
          },
          "fires": {
            "type": "integer",
            "format": "int64",
            "description": "Total graph fires since load — the reactor's live fire counter\n(CLOACI-I-0124 / WS-10). The UI derives recent throughput from the delta\nacross successive polls.",
            "minimum": 0
          },
          "health": {
            "description": "Graph health snapshot; `{\"state\": \"running\" | \"stopped\"}` when no\ndetailed health is available. Free-form JSON for now."
          },
          "input_strategy": {
            "type": [
              "string",
              "null"
            ],
            "description": "Input strategy of the bound reactor: `\"latest\"` | `\"sequential\"`."
          },
          "last_fired_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp of the last graph fire; `null` if it hasn't fired yet."
          },
          "name": {
            "type": "string"
          },
          "paused": {
            "type": "boolean",
            "description": "Pause state of the graph's reactor."
          },
          "reaction_mode": {
            "type": [
              "string",
              "null"
            ],
            "description": "Reaction mode of the bound reactor: `\"when_any\"` | `\"when_all\"`."
          },
          "reactor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Name of the reactor this graph is bound to (the trigger that fires it)."
          },
          "source_package": {
            "type": [
              "string",
              "null"
            ],
            "description": "Package whose retained source defines this graph's nodes/reactor, so the\nUI can fetch it via `GET /workflows/{package}/source` and show node code\n(CLOACI-T-0773). `None` when the package can't be resolved (e.g. a graph\ndeclaring no typed surface). Populated on the single-graph detail endpoint\nonly; the list leaves it `None`."
          },
          "topology": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/GraphTopology",
                "description": "Node/edge topology of the computation graph, for rendering its DAG.\n`None` for graphs predating topology emission. (CLOACI-T-0673)"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "GraphTopology": {
        "type": "object",
        "description": "Node/edge topology of a computation graph (CLOACI-T-0673).",
        "required": [
          "nodes",
          "edges"
        ],
        "properties": {
          "edges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GraphTopologyEdge"
            }
          },
          "nodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GraphTopologyNode"
            }
          }
        }
      },
      "GraphTopologyEdge": {
        "type": "object",
        "description": "One directed edge in a computation graph (CLOACI-T-0673).",
        "required": [
          "from",
          "to"
        ],
        "properties": {
          "from": {
            "type": "string"
          },
          "label": {
            "type": [
              "string",
              "null"
            ],
            "description": "Routing-variant label for conditional edges; `None` for linear edges."
          },
          "to": {
            "type": "string"
          }
        }
      },
      "GraphTopologyNode": {
        "type": "object",
        "description": "One compute node in a computation graph (CLOACI-T-0673).",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Node id (the compute function name)."
          },
          "inputs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Accumulator names this node reads from the input cache (entry nodes)."
          }
        }
      },
      "InjectAccumulatorRequest": {
        "type": "object",
        "description": "Request body for `POST /v1/health/accumulators/{name}/inject` (CLOACI-T-0753)\n— push a single typed event into a running accumulator, the operator-facing\nREST analogue of the WS accumulator-push path. The JSON `event` is serialized\nto the boundary wire encoding server-side, so operators never craft raw\n`Vec<u8>`.",
        "required": [
          "event"
        ],
        "properties": {
          "event": {
            "description": "The event payload (any JSON) to push to the accumulator."
          }
        }
      },
      "InjectAccumulatorResponse": {
        "type": "object",
        "description": "Response body for a successful accumulator inject (CLOACI-T-0753).",
        "required": [
          "accumulator",
          "delivered"
        ],
        "properties": {
          "accumulator": {
            "type": "string",
            "description": "Echoes the accumulator name the event was pushed to."
          },
          "delivered": {
            "type": "integer",
            "description": "Number of receivers the event was delivered to.",
            "minimum": 0
          }
        }
      },
      "InputSlot": {
        "type": "object",
        "description": "One declared input slot of an injectable surface: a named, typed value the\nsurface accepts. `schema` is a JSON Schema fragment (the type descriptor —\n`schemars`-derived for Rust, type-hint-derived for Python) that the UI can\nrender a form from and the server can validate an injection against.\n\n`required` slots must be supplied; `default` (when present) is applied when a\nslot is omitted. A surface with no declared interface exposes an empty slot\nlist (the \"undeclared\" state) and accepts free-form input.",
        "required": [
          "name",
          "schema",
          "required"
        ],
        "properties": {
          "default": {
            "type": [
              "object",
              "null"
            ],
            "description": "Optional default applied when the slot is omitted."
          },
          "encrypted": {
            "type": "boolean",
            "description": "CLOACI-I-0133 / T-0859: marks this slot as an **encrypted secret** rather\nthan a plaintext param. A secret slot is bound via a `{\"$secret\": name}`\nreference (never a literal value), resolved encrypted at fire time, and\nits resolved value never enters the durable `Context` (NFR-001). Defaults\nto `false` so pre-existing serialized slots (which omit the field)\ndeserialize as ordinary params."
          },
          "name": {
            "type": "string",
            "description": "Slot name — the context key (workflows) or source/event name\n(accumulators/reactors)."
          },
          "required": {
            "type": "boolean",
            "description": "Whether this slot must be supplied for the injection to be accepted."
          },
          "schema": {
            "type": "object",
            "description": "JSON Schema fragment describing the accepted value's type."
          }
        }
      },
      "KeyCreatedResponse": {
        "type": "object",
        "description": "`201 Created` body for a new API key. The plaintext `key` is returned\nexactly once — it cannot be retrieved again.",
        "required": [
          "id",
          "name",
          "key",
          "permissions",
          "is_admin",
          "created_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "id": {
            "type": "string",
            "description": "Key UUID."
          },
          "is_admin": {
            "type": "boolean",
            "description": "God-mode flag — never granted via the create endpoints."
          },
          "key": {
            "type": "string",
            "description": "One-time plaintext API key."
          },
          "name": {
            "type": "string"
          },
          "permissions": {
            "type": "string",
            "description": "Role string: `read` | `write` | `admin`."
          },
          "tenant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tenant scope; `null` for global keys."
          }
        }
      },
      "KeyInfo": {
        "type": "object",
        "description": "One row in the key list (`GET /auth/keys`). No hashes or plaintext.",
        "required": [
          "id",
          "name",
          "permissions",
          "is_admin",
          "created_at",
          "revoked"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "id": {
            "type": "string",
            "description": "Key UUID."
          },
          "is_admin": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "permissions": {
            "type": "string",
            "description": "Role string: `read` | `write` | `admin`."
          },
          "revoked": {
            "type": "boolean"
          },
          "tenant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tenant scope; `null` for global keys."
          }
        }
      },
      "KeyRevokedResponse": {
        "type": "object",
        "description": "`DELETE /auth/keys/{key_id}` response.",
        "required": [
          "status",
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "UUID of the revoked key."
          },
          "status": {
            "type": "string",
            "description": "Always `\"revoked\"`."
          }
        }
      },
      "KeyRole": {
        "type": "string",
        "description": "Allowed roles for API keys.",
        "enum": [
          "admin",
          "write",
          "read"
        ]
      },
      "ListResponse_AccountInfo": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "Public view of a local account (never the password hash).",
              "required": [
                "id",
                "username",
                "role",
                "status"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "role": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                },
                "username": {
                  "type": "string"
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ListResponse_AccumulatorStatus": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in `GET /v1/health/accumulators`.",
              "required": [
                "name",
                "status"
              ],
              "properties": {
                "buffer_capacity": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "format": "int64",
                  "description": "Declared buffer capacity for bounded kinds — state `capacity = N`, batch\n`max_buffer_size`. `None` when unbounded or not applicable. The UI\nrenders `buffer_depth/buffer_capacity` as fill (CLOACI-T-0744).",
                  "minimum": 0
                },
                "buffer_depth": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "format": "int64",
                  "description": "Buffered-event count for buffering kinds — batch (events awaiting flush)\nand state (window entries). `None` for kinds that don't buffer\n(passthrough/stream/polling) or runtimes predating the gauge\n(CLOACI-T-0744).",
                  "minimum": 0
                },
                "error": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Degradation detail when the source is unhealthy (e.g. connection error)."
                },
                "events_total": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "format": "int64",
                  "description": "Total boundaries emitted since load (monotonic). `None` when untracked.",
                  "minimum": 0
                },
                "last_event_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Wall-clock of the last boundary this accumulator emitted (RFC3339), or\n`None` if it hasn't emitted yet / the runtime predates freshness tracking."
                },
                "last_operator_inject_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 time of the last operator inject, or `None` if never\n(CLOACI-T-0776)."
                },
                "name": {
                  "type": "string"
                },
                "operator_injects": {
                  "type": "integer",
                  "format": "int64",
                  "description": "Number of operator injects into this accumulator since load\n(CLOACI-T-0776) — manual interventions via the REST/WS inject paths. `0`\nwhen never injected. The UI marks injected accumulators with a \"manual\" pill.",
                  "minimum": 0
                },
                "reactor": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "The reactor (graph) this accumulator feeds, self-registered by the graph\nat load (CLOACI-I-0128 follow-up). `None` for older runtimes that didn't\nregister the descriptor. Lets an operator see what pushing to\n`/v1/ws/accumulator/{name}` actually drives."
                },
                "state": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Health state label (`live`/`socket_only`/`disconnected`/…), CLOACI-T-0765.\nMirrors the `state` inside `status`; promoted to a typed field for the UI."
                },
                "status": {
                  "description": "Accumulator health as reported by the endpoint registry. Free-form\nJSON for now; structured in a later contract revision."
                },
                "tenant_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Owning tenant, or `None` for untagged single-tenant graphs."
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ListResponse_AgentInfo": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One registered execution agent in the in-memory fleet roster.",
              "required": [
                "agent_id",
                "target_triple",
                "max_concurrency",
                "in_flight",
                "available_capacity",
                "seconds_since_heartbeat",
                "capabilities"
              ],
              "properties": {
                "agent_id": {
                  "type": "string"
                },
                "available_capacity": {
                  "type": "integer",
                  "format": "int32",
                  "minimum": 0
                },
                "capabilities": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "in_flight": {
                  "type": "integer",
                  "format": "int32",
                  "minimum": 0
                },
                "max_concurrency": {
                  "type": "integer",
                  "format": "int32",
                  "minimum": 0
                },
                "seconds_since_heartbeat": {
                  "type": "integer",
                  "format": "int64",
                  "description": "Seconds since this agent's last heartbeat — the liveness signal an\noperator reads (the underlying record stores a monotonic `Instant`,\nnot a wall-clock time).",
                  "minimum": 0
                },
                "target_triple": {
                  "type": "string"
                },
                "tenant_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Tenant scope the agent registered under, if any."
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ListResponse_GraphStatus": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in `GET /v1/health/graphs`, and the `GET /v1/health/graphs/{name}`\nresponse body.",
              "required": [
                "name",
                "health",
                "accumulators",
                "paused"
              ],
              "properties": {
                "accumulators": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Names of the accumulators feeding this graph."
                },
                "fires": {
                  "type": "integer",
                  "format": "int64",
                  "description": "Total graph fires since load — the reactor's live fire counter\n(CLOACI-I-0124 / WS-10). The UI derives recent throughput from the delta\nacross successive polls.",
                  "minimum": 0
                },
                "health": {
                  "description": "Graph health snapshot; `{\"state\": \"running\" | \"stopped\"}` when no\ndetailed health is available. Free-form JSON for now."
                },
                "input_strategy": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Input strategy of the bound reactor: `\"latest\"` | `\"sequential\"`."
                },
                "last_fired_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp of the last graph fire; `null` if it hasn't fired yet."
                },
                "name": {
                  "type": "string"
                },
                "paused": {
                  "type": "boolean",
                  "description": "Pause state of the graph's reactor."
                },
                "reaction_mode": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Reaction mode of the bound reactor: `\"when_any\"` | `\"when_all\"`."
                },
                "reactor": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Name of the reactor this graph is bound to (the trigger that fires it)."
                },
                "source_package": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Package whose retained source defines this graph's nodes/reactor, so the\nUI can fetch it via `GET /workflows/{package}/source` and show node code\n(CLOACI-T-0773). `None` when the package can't be resolved (e.g. a graph\ndeclaring no typed surface). Populated on the single-graph detail endpoint\nonly; the list leaves it `None`."
                },
                "topology": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GraphTopology",
                      "description": "Node/edge topology of the computation graph, for rendering its DAG.\n`None` for graphs predating topology emission. (CLOACI-T-0673)"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ListResponse_KeyInfo": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in the key list (`GET /auth/keys`). No hashes or plaintext.",
              "required": [
                "id",
                "name",
                "permissions",
                "is_admin",
                "created_at",
                "revoked"
              ],
              "properties": {
                "created_at": {
                  "type": "string",
                  "description": "RFC 3339 timestamp."
                },
                "id": {
                  "type": "string",
                  "description": "Key UUID."
                },
                "is_admin": {
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                },
                "permissions": {
                  "type": "string",
                  "description": "Role string: `read` | `write` | `admin`."
                },
                "revoked": {
                  "type": "boolean"
                },
                "tenant_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Tenant scope; `null` for global keys."
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ListResponse_ReactorFire": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One recorded reactor fire (CLOACI-T-0766) — a row in\n`GET /v1/health/reactors/{name}/fires`. Makes fires observable (outcome +\nduration), not just counted.",
              "required": [
                "fired_at",
                "ok",
                "duration_ms"
              ],
              "properties": {
                "duration_ms": {
                  "type": "integer",
                  "format": "int64",
                  "description": "Graph execution wall-clock for this fire, in milliseconds.",
                  "minimum": 0
                },
                "error": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Error detail for a failed fire."
                },
                "fired_at": {
                  "type": "string",
                  "description": "RFC 3339 time the fire completed."
                },
                "inputs": {
                  "type": "object",
                  "description": "Input boundary values that triggered this fire: source name → value\n(CLOACI-T-0775). The graph's I/O history, so a fire reads as more than\n\"ran in 0ms\".",
                  "additionalProperties": {},
                  "propertyNames": {
                    "type": "string"
                  }
                },
                "manual": {
                  "type": "boolean",
                  "description": "Whether this fire was a manual operator intervention\n(`force_fire`/`fire_with`) rather than a criteria-driven fire over real\nboundary events (CLOACI-T-0776). The UI marks it with a \"manual\" pill."
                },
                "ok": {
                  "type": "boolean",
                  "description": "Whether the graph execution completed (`false` = errored)."
                },
                "outputs": {
                  "type": "array",
                  "items": {},
                  "description": "Terminal outputs the graph produced for this fire, as JSON\n(CLOACI-T-0775). Empty when the executor can't serialize them (e.g. the\nPython reactor path) or on a failed fire."
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ListResponse_ReactorStatus": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in `GET /v1/health/reactors` (CLOACI-T-0742). Reactor-first view:\nreactors are standalone (a graph binds to a reactor, not vice versa), so a\nreactor with no graph bound appears here but not in `GET /v1/health/graphs`.",
              "required": [
                "name",
                "health",
                "accumulators",
                "paused"
              ],
              "properties": {
                "accumulators": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Accumulators this reactor consumes (its inputs)."
                },
                "bound_graphs": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Graphs bound to this reactor; empty when the reactor has no graph yet."
                },
                "fires": {
                  "type": "integer",
                  "format": "int64",
                  "description": "Total fires since load (the reactor's live fire counter, WS-10).",
                  "minimum": 0
                },
                "health": {
                  "description": "Reactor health snapshot; `{\"state\": \"running\" | \"stopped\"}` when no\ndetailed health is available. Free-form JSON, mirroring `GraphStatus`."
                },
                "input_strategy": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Input strategy: `\"latest\"` | `\"sequential\"`."
                },
                "last_fired_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp of the last fire; `null` if it hasn't fired yet."
                },
                "name": {
                  "type": "string"
                },
                "paused": {
                  "type": "boolean",
                  "description": "Pause state of the reactor."
                },
                "reaction_mode": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Firing criteria: `\"when_any\"` | `\"when_all\"`."
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ListResponse_SecretMetadataResponse": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "Metadata view of a secret — the ONLY shape a read returns. Carries names +\ntimestamps; **never** a plaintext or ciphertext value.",
              "required": [
                "id",
                "name",
                "field_names",
                "created_at",
                "updated_at"
              ],
              "properties": {
                "created_at": {
                  "type": "string",
                  "description": "RFC 3339 timestamp."
                },
                "field_names": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "The declared field names (no values)."
                },
                "id": {
                  "type": "string",
                  "description": "Secret UUID."
                },
                "name": {
                  "type": "string",
                  "description": "The secret's name."
                },
                "updated_at": {
                  "type": "string",
                  "description": "RFC 3339 timestamp."
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ListResponse_TenantSummary": {
        "type": "object",
        "description": "Unified list envelope (CLOACI-T-0594 / API-03): every list endpoint\nreturns `{items, total}`. `total` is best-effort — it equals the\nreturned page size when the server doesn't run a separate COUNT.",
        "required": [
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in the tenant list (`GET /tenants`).",
              "required": [
                "name"
              ],
              "properties": {
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "LocalLoginRequest": {
        "type": "object",
        "description": "A local-login attempt. `tenant` selects which tenant's account namespace to\nauthenticate against (`None` = a global account).",
        "required": [
          "username",
          "password"
        ],
        "properties": {
          "password": {
            "type": "string"
          },
          "tenant": {
            "type": [
              "string",
              "null"
            ]
          },
          "username": {
            "type": "string"
          }
        }
      },
      "LocalLoginResponse": {
        "type": "object",
        "description": "A successful local login. `key` is the minted bearer key — shown exactly\nonce; the SPA stores it (sessionStorage) and presents it as `Bearer`.",
        "required": [
          "key",
          "role"
        ],
        "properties": {
          "expires_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "key": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "tenant_id": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "LogoutResponse": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string"
          }
        }
      },
      "PackageUploadForm": {
        "type": "object",
        "description": "Multipart form for workflow package upload. Spec-only type: the handler\naccepts the first file field regardless of name; `file` is the\nconventional field name.",
        "required": [
          "file"
        ],
        "properties": {
          "file": {
            "type": "string",
            "format": "binary",
            "description": "The `.cloacina` package archive.",
            "contentMediaType": "application/octet-stream"
          }
        }
      },
      "ReactorFire": {
        "type": "object",
        "description": "One recorded reactor fire (CLOACI-T-0766) — a row in\n`GET /v1/health/reactors/{name}/fires`. Makes fires observable (outcome +\nduration), not just counted.",
        "required": [
          "fired_at",
          "ok",
          "duration_ms"
        ],
        "properties": {
          "duration_ms": {
            "type": "integer",
            "format": "int64",
            "description": "Graph execution wall-clock for this fire, in milliseconds.",
            "minimum": 0
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Error detail for a failed fire."
          },
          "fired_at": {
            "type": "string",
            "description": "RFC 3339 time the fire completed."
          },
          "inputs": {
            "type": "object",
            "description": "Input boundary values that triggered this fire: source name → value\n(CLOACI-T-0775). The graph's I/O history, so a fire reads as more than\n\"ran in 0ms\".",
            "additionalProperties": {},
            "propertyNames": {
              "type": "string"
            }
          },
          "manual": {
            "type": "boolean",
            "description": "Whether this fire was a manual operator intervention\n(`force_fire`/`fire_with`) rather than a criteria-driven fire over real\nboundary events (CLOACI-T-0776). The UI marks it with a \"manual\" pill."
          },
          "ok": {
            "type": "boolean",
            "description": "Whether the graph execution completed (`false` = errored)."
          },
          "outputs": {
            "type": "array",
            "items": {},
            "description": "Terminal outputs the graph produced for this fire, as JSON\n(CLOACI-T-0775). Empty when the executor can't serialize them (e.g. the\nPython reactor path) or on a failed fire."
          }
        }
      },
      "ReactorFireTimeseries": {
        "type": "object",
        "description": "`GET /v1/health/reactors/{name}/fires/timeseries` (CLOACI-T-0766): fire counts\nper minute for the last 60 minutes, oldest → newest, gaps filled with 0.",
        "required": [
          "buckets"
        ],
        "properties": {
          "buckets": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "description": "60 per-minute fire counts, oldest first; the last entry is the current minute."
          }
        }
      },
      "ReactorStatus": {
        "type": "object",
        "description": "One row in `GET /v1/health/reactors` (CLOACI-T-0742). Reactor-first view:\nreactors are standalone (a graph binds to a reactor, not vice versa), so a\nreactor with no graph bound appears here but not in `GET /v1/health/graphs`.",
        "required": [
          "name",
          "health",
          "accumulators",
          "paused"
        ],
        "properties": {
          "accumulators": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Accumulators this reactor consumes (its inputs)."
          },
          "bound_graphs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Graphs bound to this reactor; empty when the reactor has no graph yet."
          },
          "fires": {
            "type": "integer",
            "format": "int64",
            "description": "Total fires since load (the reactor's live fire counter, WS-10).",
            "minimum": 0
          },
          "health": {
            "description": "Reactor health snapshot; `{\"state\": \"running\" | \"stopped\"}` when no\ndetailed health is available. Free-form JSON, mirroring `GraphStatus`."
          },
          "input_strategy": {
            "type": [
              "string",
              "null"
            ],
            "description": "Input strategy: `\"latest\"` | `\"sequential\"`."
          },
          "last_fired_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp of the last fire; `null` if it hasn't fired yet."
          },
          "name": {
            "type": "string"
          },
          "paused": {
            "type": "boolean",
            "description": "Pause state of the reactor."
          },
          "reaction_mode": {
            "type": [
              "string",
              "null"
            ],
            "description": "Firing criteria: `\"when_any\"` | `\"when_all\"`."
          }
        }
      },
      "ResetPasswordRequest": {
        "type": "object",
        "description": "Reset a local account's password (admin-reset-only, OQ-12).",
        "required": [
          "password"
        ],
        "properties": {
          "password": {
            "type": "string"
          }
        }
      },
      "RotateSecretRequest": {
        "type": "object",
        "description": "Request body for `PUT|POST /v1/tenants/{tenant_id}/secrets/{name}` — rotate.\n\nReplaces the secret's field map in place (D-8/OQ-5: in-place, no versioning).",
        "required": [
          "fields"
        ],
        "properties": {
          "fields": {
            "type": "object",
            "description": "The new `{field: value}` map. Values are write-only.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          }
        }
      },
      "SecretDeletedResponse": {
        "type": "object",
        "description": "`DELETE /v1/tenants/{tenant_id}/secrets/{name}` response.",
        "required": [
          "status",
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "The deleted secret's name."
          },
          "status": {
            "type": "string",
            "description": "Always `\"deleted\"`."
          }
        }
      },
      "SecretMetadataResponse": {
        "type": "object",
        "description": "Metadata view of a secret — the ONLY shape a read returns. Carries names +\ntimestamps; **never** a plaintext or ciphertext value.",
        "required": [
          "id",
          "name",
          "field_names",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "field_names": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The declared field names (no values)."
          },
          "id": {
            "type": "string",
            "description": "Secret UUID."
          },
          "name": {
            "type": "string",
            "description": "The secret's name."
          },
          "updated_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          }
        }
      },
      "TaskExecutionDetail": {
        "type": "object",
        "description": "One per-task row of an execution (CLOACI-I-0124 / WS-1).",
        "required": [
          "id",
          "task_name",
          "status",
          "attempt",
          "max_attempts",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "attempt": {
            "type": "integer",
            "format": "int32"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp; `null` while still running."
          },
          "created_at": {
            "type": "string",
            "description": "Row-created timestamp (RFC 3339) — always present; a fallback \"start\"\nwhen `started_at` is null (some runner configs don't stamp it)."
          },
          "error_details": {
            "type": [
              "string",
              "null"
            ],
            "description": "Structured error details, when present."
          },
          "id": {
            "type": "string",
            "description": "Task execution UUID."
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last error message for the most recent failed attempt, when present."
          },
          "max_attempts": {
            "type": "integer",
            "format": "int32"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp; `null` until the task starts."
          },
          "status": {
            "type": "string"
          },
          "sub_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "`sub_status` qualifier (e.g. deferral), when present."
          },
          "task_name": {
            "type": "string",
            "description": "Task identifier within the workflow."
          },
          "updated_at": {
            "type": "string",
            "description": "Row-updated timestamp (RFC 3339) — always present; a fallback \"end\"."
          }
        }
      },
      "TenantCreatedResponse": {
        "type": "object",
        "description": "`201 Created` body for a new tenant. Password and connection string are\nintentionally excluded to prevent credential leakage (SEC-08).",
        "required": [
          "name",
          "username"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "username": {
            "type": "string"
          }
        }
      },
      "TenantListResponse_ExecutionSummary": {
        "type": "object",
        "description": "List envelope variant that retains a top-level `tenant_id`, used by\ntenant-scoped list endpoints for backward compatibility with operator\ndashboards that key off it.",
        "required": [
          "tenant_id",
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in the executions list.",
              "required": [
                "id",
                "workflow_name",
                "status",
                "started_at"
              ],
              "properties": {
                "completed_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp; `null` while still running."
                },
                "id": {
                  "type": "string",
                  "description": "Execution UUID."
                },
                "started_at": {
                  "type": "string",
                  "description": "RFC 3339 timestamp."
                },
                "status": {
                  "type": "string"
                },
                "trigger_origin": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "How the run was triggered (CLOACI-T-0776): `\"manual\"` for an operator run\nvia the REST execute endpoint; `null` for cron/trigger/reactor-driven runs.\nThe UI marks manual runs with a \"manual\" pill."
                },
                "workflow_name": {
                  "type": "string"
                }
              }
            }
          },
          "tenant_id": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "TenantListResponse_TriggerScheduleSummary": {
        "type": "object",
        "description": "List envelope variant that retains a top-level `tenant_id`, used by\ntenant-scoped list endpoints for backward compatibility with operator\ndashboards that key off it.",
        "required": [
          "tenant_id",
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in the trigger list.",
              "required": [
                "id",
                "schedule_type",
                "workflow_name",
                "enabled",
                "created_at"
              ],
              "properties": {
                "created_at": {
                  "type": "string",
                  "description": "RFC 3339 timestamp."
                },
                "cron_expression": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "enabled": {
                  "type": "boolean"
                },
                "id": {
                  "type": "string",
                  "description": "Schedule UUID."
                },
                "last_poll_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp of the scheduler's last poll of this trigger\n(`trigger`-type schedules only; `None` for cron or never-polled).\nThe next poll is due `poll_interval_ms` after this (CLOACI-T-0938)."
                },
                "last_run_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp."
                },
                "next_run_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp."
                },
                "paused": {
                  "type": "boolean",
                  "description": "Whether the schedule is paused (CLOACI-T-0749). A paused schedule is not\nfired by the scheduler until resumed; distinct from `enabled`."
                },
                "paused_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp of when it was paused, if paused."
                },
                "poll_interval_ms": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "format": "int64"
                },
                "schedule_type": {
                  "type": "string",
                  "description": "`cron` or `trigger`."
                },
                "trigger_name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "workflow_name": {
                  "type": "string"
                }
              }
            }
          },
          "tenant_id": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "TenantListResponse_WorkflowInstanceSummary": {
        "type": "object",
        "description": "List envelope variant that retains a top-level `tenant_id`, used by\ntenant-scoped list endpoints for backward compatibility with operator\ndashboards that key off it.",
        "required": [
          "tenant_id",
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in the instance list, and the body of a single-instance GET.",
              "required": [
                "id",
                "workflow_name",
                "instance_name",
                "enabled",
                "created_at"
              ],
              "properties": {
                "created_at": {
                  "type": "string",
                  "description": "RFC 3339 timestamp."
                },
                "cron_expression": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "enabled": {
                  "type": "boolean"
                },
                "id": {
                  "type": "string",
                  "description": "Underlying schedule UUID."
                },
                "instance_name": {
                  "type": "string"
                },
                "last_run_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp."
                },
                "next_run_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "RFC 3339 timestamp."
                },
                "params": {
                  "description": "Bound parameter values, as stored."
                },
                "paused": {
                  "type": "boolean",
                  "description": "Whether the schedule is paused (distinct from `enabled`)."
                },
                "timezone": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "workflow_name": {
                  "type": "string"
                }
              }
            }
          },
          "tenant_id": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "TenantListResponse_WorkflowSummary": {
        "type": "object",
        "description": "List envelope variant that retains a top-level `tenant_id`, used by\ntenant-scoped list endpoints for backward compatibility with operator\ndashboards that key off it.",
        "required": [
          "tenant_id",
          "items",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One row in the workflow list (`GET /tenants/{tenant_id}/workflows`).",
              "required": [
                "id",
                "package_name",
                "workflow_name",
                "version",
                "tasks",
                "created_at"
              ],
              "properties": {
                "created_at": {
                  "type": "string",
                  "description": "RFC 3339 timestamp."
                },
                "description": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "id": {
                  "type": "string",
                  "description": "Package UUID."
                },
                "package_name": {
                  "type": "string"
                },
                "paused": {
                  "type": "boolean",
                  "description": "Whether this workflow is paused (CLOACI-T-0749). Paused workflows refuse\nnew executions until resumed."
                },
                "tasks": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Task IDs included in this package."
                },
                "version": {
                  "type": "string"
                },
                "workflow_name": {
                  "type": "string",
                  "description": "Executable workflow name (the identifier to execute by). Differs from\n`package_name` under the standard convention (package `demo-slow-rust`\n→ workflow `demo_slow_workflow`). Falls back to `package_name` for\npackages predating workflow-name persistence. (CLOACI-T-0671)"
                }
              }
            }
          },
          "tenant_id": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "TenantRemovedResponse": {
        "type": "object",
        "description": "`DELETE /tenants/{schema_name}` response — orchestrated teardown report.",
        "required": [
          "status",
          "schema_name",
          "revoked_keys",
          "runner_evicted",
          "db_cache_evicted"
        ],
        "properties": {
          "db_cache_evicted": {
            "type": "boolean"
          },
          "revoked_keys": {
            "type": "integer",
            "description": "Number of still-active API keys revoked during teardown.",
            "minimum": 0
          },
          "runner_evicted": {
            "type": "boolean"
          },
          "schema_name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Always `\"removed\"`."
          }
        }
      },
      "TenantSummary": {
        "type": "object",
        "description": "One row in the tenant list (`GET /tenants`).",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          }
        }
      },
      "TriggerDetailResponse": {
        "type": "object",
        "description": "`GET /tenants/{tenant_id}/triggers/{name}` response.",
        "required": [
          "tenant_id",
          "schedule",
          "recent_executions"
        ],
        "properties": {
          "recent_executions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TriggerExecution"
            }
          },
          "schedule": {
            "$ref": "#/components/schemas/TriggerScheduleInfo"
          },
          "tenant_id": {
            "type": "string"
          }
        }
      },
      "TriggerExecution": {
        "type": "object",
        "description": "One row in `recent_executions` of the trigger detail response.",
        "required": [
          "id",
          "started_at"
        ],
        "properties": {
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp."
          },
          "id": {
            "type": "string",
            "description": "Schedule-execution UUID."
          },
          "scheduled_time": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp."
          },
          "started_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          }
        }
      },
      "TriggerPauseResponse": {
        "type": "object",
        "description": "`POST /tenants/{tenant_id}/triggers/{name}/pause` and `/resume` response\n(CLOACI-T-0749).",
        "required": [
          "tenant_id",
          "id",
          "name",
          "status",
          "paused"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Schedule UUID."
          },
          "name": {
            "type": "string",
            "description": "The name the schedule was addressed by (trigger or workflow name)."
          },
          "paused": {
            "type": "boolean",
            "description": "Current paused state after the operation."
          },
          "status": {
            "type": "string",
            "description": "`\"paused\"` or `\"resumed\"`."
          },
          "tenant_id": {
            "type": "string"
          }
        }
      },
      "TriggerScheduleInfo": {
        "type": "object",
        "description": "Schedule fields in the trigger detail response.",
        "required": [
          "id",
          "schedule_type",
          "workflow_name",
          "enabled"
        ],
        "properties": {
          "cron_expression": {
            "type": [
              "string",
              "null"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "description": "Schedule UUID."
          },
          "paused": {
            "type": "boolean",
            "description": "Whether the schedule is paused (CLOACI-T-0749)."
          },
          "paused_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp of when it was paused, if paused."
          },
          "poll_interval_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Poll interval in milliseconds for `trigger`-type schedules (the\ncustom-poll cadence). `None` for cron schedules. Lets the Triggers\ndetail view show \"polls every Ns\" (CLOACI-I-0124 / WS-6)."
          },
          "schedule_type": {
            "type": "string",
            "description": "`cron` or `trigger`."
          },
          "trigger_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "workflow_name": {
            "type": "string"
          }
        }
      },
      "TriggerScheduleSummary": {
        "type": "object",
        "description": "One row in the trigger list.",
        "required": [
          "id",
          "schedule_type",
          "workflow_name",
          "enabled",
          "created_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "cron_expression": {
            "type": [
              "string",
              "null"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "description": "Schedule UUID."
          },
          "last_poll_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp of the scheduler's last poll of this trigger\n(`trigger`-type schedules only; `None` for cron or never-polled).\nThe next poll is due `poll_interval_ms` after this (CLOACI-T-0938)."
          },
          "last_run_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp."
          },
          "next_run_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp."
          },
          "paused": {
            "type": "boolean",
            "description": "Whether the schedule is paused (CLOACI-T-0749). A paused schedule is not\nfired by the scheduler until resumed; distinct from `enabled`."
          },
          "paused_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp of when it was paused, if paused."
          },
          "poll_interval_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "schedule_type": {
            "type": "string",
            "description": "`cron` or `trigger`."
          },
          "trigger_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "workflow_name": {
            "type": "string"
          }
        }
      },
      "WhoamiResponse": {
        "type": "object",
        "description": "The caller's own identity + role (CLOACI-T-0803) — lets the UI gate\nwrite/admin controls to the key's role instead of offering actions that\nwould 403.",
        "required": [
          "role",
          "is_admin",
          "name"
        ],
        "properties": {
          "is_admin": {
            "type": "boolean",
            "description": "God-mode flag (cross-tenant platform admin)."
          },
          "name": {
            "type": "string",
            "description": "The key's display name."
          },
          "role": {
            "type": "string",
            "description": "Role within the tenant: `read` | `write` | `admin`."
          },
          "tenant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tenant the key is scoped to (`None` = global/public)."
          }
        }
      },
      "WorkflowDeletedResponse": {
        "type": "object",
        "description": "`DELETE /tenants/{tenant_id}/workflows/{name}/{version}` response.",
        "required": [
          "status",
          "package_name",
          "version"
        ],
        "properties": {
          "package_name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Always `\"deleted\"`."
          },
          "version": {
            "type": "string"
          }
        }
      },
      "WorkflowDetail": {
        "type": "object",
        "description": "`GET /tenants/{tenant_id}/workflows/{name}` response — summary fields\nplus real build state (pending/building/failed/success).",
        "required": [
          "tenant_id",
          "id",
          "package_name",
          "workflow_name",
          "version",
          "tasks",
          "created_at",
          "build_status"
        ],
        "properties": {
          "build_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "build_status": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "declared_params": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InputSlot"
            },
            "description": "CLOACI-I-0128: declared input params (named, JSON-Schema-typed slots) the\nworkflow accepts at execute time. Empty when undeclared. Lets the UI\nrender a typed execute form and the server validate context."
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string",
            "description": "Package UUID."
          },
          "package_name": {
            "type": "string"
          },
          "paused": {
            "type": "boolean",
            "description": "Whether this workflow is paused (CLOACI-T-0749). Paused workflows refuse\nnew executions until resumed."
          },
          "task_graph": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowTaskNode"
            },
            "description": "The task dependency graph (nodes + their upstream dependencies) for\nrendering the full workflow DAG. Empty for packages predating\ntask-graph persistence. (CLOACI-T-0663)"
          },
          "tasks": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Task IDs included in this package."
          },
          "tenant_id": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "workflow_name": {
            "type": "string",
            "description": "Executable workflow name (the identifier to execute by). Differs from\n`package_name` under the standard convention (package `demo-slow-rust`\n→ workflow `demo_slow_workflow`). Falls back to `package_name` for\npackages predating workflow-name persistence. (CLOACI-T-0671)"
          }
        }
      },
      "WorkflowInstanceSummary": {
        "type": "object",
        "description": "One row in the instance list, and the body of a single-instance GET.",
        "required": [
          "id",
          "workflow_name",
          "instance_name",
          "enabled",
          "created_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "cron_expression": {
            "type": [
              "string",
              "null"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "description": "Underlying schedule UUID."
          },
          "instance_name": {
            "type": "string"
          },
          "last_run_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp."
          },
          "next_run_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "RFC 3339 timestamp."
          },
          "params": {
            "description": "Bound parameter values, as stored."
          },
          "paused": {
            "type": "boolean",
            "description": "Whether the schedule is paused (distinct from `enabled`)."
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ]
          },
          "workflow_name": {
            "type": "string"
          }
        }
      },
      "WorkflowPauseResponse": {
        "type": "object",
        "description": "`POST /tenants/{tenant_id}/workflows/{name}/pause` and `/resume` response\n(CLOACI-T-0749).",
        "required": [
          "tenant_id",
          "id",
          "name",
          "status",
          "paused"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Package UUID of the affected workflow."
          },
          "name": {
            "type": "string",
            "description": "The name the workflow was addressed by (workflow or package name)."
          },
          "paused": {
            "type": "boolean",
            "description": "Current paused state after the operation."
          },
          "status": {
            "type": "string",
            "description": "`\"paused\"` or `\"resumed\"`."
          },
          "tenant_id": {
            "type": "string"
          }
        }
      },
      "WorkflowSourceFile": {
        "type": "object",
        "description": "One source file from a workflow package's retained `.cloacina` archive,\nsurfaced read-only for display (CLOACI-T-0750).",
        "required": [
          "path",
          "contents"
        ],
        "properties": {
          "contents": {
            "type": "string",
            "description": "UTF-8 file contents."
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "Best-effort language id derived from the file extension (`\"rust\"`,\n`\"python\"`, `\"toml\"`, …), for syntax highlighting. `None` when unknown."
          },
          "path": {
            "type": "string",
            "description": "Path relative to the package source root, using forward slashes\n(e.g. `\"src/lib.rs\"`, `\"package.toml\"`)."
          }
        }
      },
      "WorkflowSourceResponse": {
        "type": "object",
        "description": "`GET /tenants/{tenant_id}/workflows/{name}/source` response — the original\nsource retained in the package's `.cloacina` archive, surfaced read-only\n(CLOACI-T-0750). The source is independent of build state, so it is\navailable even for packages that are still building or failed to build.",
        "required": [
          "tenant_id",
          "id",
          "package_name",
          "workflow_name",
          "version",
          "files"
        ],
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowSourceFile"
            },
            "description": "Source files in the package, sorted by path. Binary and oversized files\nare omitted."
          },
          "id": {
            "type": "string",
            "description": "Package UUID."
          },
          "package_name": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "workflow_name": {
            "type": "string",
            "description": "Executable workflow name (see `WorkflowSummary::workflow_name`)."
          }
        }
      },
      "WorkflowSummary": {
        "type": "object",
        "description": "One row in the workflow list (`GET /tenants/{tenant_id}/workflows`).",
        "required": [
          "id",
          "package_name",
          "workflow_name",
          "version",
          "tasks",
          "created_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "description": "RFC 3339 timestamp."
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string",
            "description": "Package UUID."
          },
          "package_name": {
            "type": "string"
          },
          "paused": {
            "type": "boolean",
            "description": "Whether this workflow is paused (CLOACI-T-0749). Paused workflows refuse\nnew executions until resumed."
          },
          "tasks": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Task IDs included in this package."
          },
          "version": {
            "type": "string"
          },
          "workflow_name": {
            "type": "string",
            "description": "Executable workflow name (the identifier to execute by). Differs from\n`package_name` under the standard convention (package `demo-slow-rust`\n→ workflow `demo_slow_workflow`). Falls back to `package_name` for\npackages predating workflow-name persistence. (CLOACI-T-0671)"
          }
        }
      },
      "WorkflowTaskNode": {
        "type": "object",
        "description": "One node in a workflow's task dependency graph — a task plus the ids of the\ntasks it depends on. The UI renders these as a DAG. (CLOACI-T-0663)",
        "required": [
          "id",
          "dependencies"
        ],
        "properties": {
          "dependencies": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Local ids of the tasks this task depends on (its incoming edges)."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional human-readable task description."
          },
          "doc_what": {
            "type": [
              "string",
              "null"
            ],
            "description": "CLOACI-T-0752 \"what\" — short summary parsed from the task's\ndoc-comment/docstring at build time. `None` when undocumented."
          },
          "doc_why": {
            "type": [
              "string",
              "null"
            ],
            "description": "CLOACI-T-0752 \"why\" — rationale parsed from the doc-comment/docstring.\n`None` when undocumented."
          },
          "id": {
            "type": "string",
            "description": "Local task id (the node id), e.g. `\"validate\"`."
          }
        }
      },
      "WorkflowUploadedResponse": {
        "type": "object",
        "description": "`201 Created` body for a workflow package upload\n(`POST /tenants/{tenant_id}/workflows`, multipart).",
        "required": [
          "package_id",
          "tenant_id"
        ],
        "properties": {
          "package_id": {
            "type": "string",
            "description": "UUID of the registered package."
          },
          "tenant_id": {
            "type": "string"
          }
        }
      },
      "WsTicketResponse": {
        "type": "object",
        "description": "`POST /auth/ws-ticket` response — a single-use, short-lived ticket for\nWebSocket upgrade auth (avoids long-lived API keys in URLs).",
        "required": [
          "ticket",
          "expires_in_seconds"
        ],
        "properties": {
          "expires_in_seconds": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "ticket": {
            "type": "string"
          }
        }
      }
    },
    "securitySchemes": {
      "api_key": {
        "type": "http",
        "scheme": "bearer",
        "description": "Cloacina API key, sent as `Authorization: Bearer <key>`. Tenant scope is carried by the key itself; tenant-scoped routes additionally name the tenant in the path."
      }
    }
  },
  "tags": [
    {
      "name": "operational",
      "description": "Liveness/readiness (no auth)"
    },
    {
      "name": "keys",
      "description": "API key management"
    },
    {
      "name": "tenants",
      "description": "Tenant lifecycle (admin)"
    },
    {
      "name": "workflows",
      "description": "Workflow package registry"
    },
    {
      "name": "triggers",
      "description": "Cron + trigger schedules (read-only)"
    },
    {
      "name": "executions",
      "description": "Workflow execution + event log"
    },
    {
      "name": "fleet",
      "description": "Execution-agent fleet roster (admin)"
    },
    {
      "name": "compiler",
      "description": "Compiler / build-pipeline status (admin)"
    },
    {
      "name": "graph-health",
      "description": "Computation-graph health"
    }
  ]
}
