{
  "openapi": "3.1.0",
  "info": {
    "title": "Sparkient API",
    "description": "Decision intelligence infrastructure for developers. Multi-stage pipeline (CEL rules \u2192 compiled classifier \u2192 optional LLM escalation) with a measured under-100ms target for the compiled stage.",
    "version": "1.0.0"
  },
  "paths": {
    "/": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "Root",
        "description": "API info \u2014 public landing page for the service.",
        "operationId": "root__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "Health",
        "description": "Liveness probe \u2014 always returns OK if the process is running.",
        "operationId": "health_health_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": {
                    "type": "string"
                  },
                  "type": "object",
                  "title": "Response Health Health Get"
                }
              }
            }
          }
        }
      }
    },
    "/ready": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "Readiness",
        "description": "Readiness probe \u2014 checks DB, Redis, and model availability.",
        "operationId": "readiness_ready_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "boolean"
                      },
                      {
                        "type": "integer"
                      }
                    ]
                  },
                  "type": "object",
                  "title": "Response Readiness Ready Get"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/credits": {
      "get": {
        "tags": [
          "credits"
        ],
        "summary": "Get Credits",
        "description": "Return the org's current credit balance.\n\nWorks with both API key and Firebase JWT authentication.\nUse this to check your balance before running expensive operations.",
        "operationId": "get_credits_api_v1_credits_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditBalanceResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/credits/usage": {
      "get": {
        "tags": [
          "credits"
        ],
        "summary": "Get Credit Usage",
        "description": "Return paginated usage history with aggregated summary.\n\nWorks with both API key and Firebase JWT authentication.\nUse this to understand what's consuming your credits.",
        "operationId": "get_credit_usage_api_v1_credits_usage_get",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 90,
              "minimum": 1,
              "description": "Lookback window in days",
              "default": 7,
              "title": "Days"
            },
            "description": "Lookback window in days"
          },
          {
            "name": "operation",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by operation type",
              "title": "Operation"
            },
            "description": "Filter by operation type"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Page Size"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditUsageResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types": {
      "post": {
        "tags": [
          "decision-types"
        ],
        "summary": "Create Decision Type",
        "description": "Create a new decision type with its first version.",
        "operationId": "create_decision_type_api_v1_decision_types_post",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionTypeCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionTypeResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "decision-types"
        ],
        "summary": "List Decision Types",
        "description": "List all decision types with pagination.",
        "operationId": "list_decision_types_api_v1_decision_types_get",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Page Size"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response List Decision Types Api V1 Decision Types Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}": {
      "get": {
        "tags": [
          "decision-types"
        ],
        "summary": "Get Decision Type",
        "description": "Get a decision type by ID with its active version.",
        "operationId": "get_decision_type_api_v1_decision_types__decision_type_id__get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionTypeResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "decision-types"
        ],
        "summary": "Update Decision Type",
        "description": "Update a decision type.\n\nOnly creates a new immutable version when logic fields change\n(options, reason_codes, hard_rules, input_schema,\nconfidence_thresholds, escalation_policy).  Metadata-only changes\n(name, description, pii_fields, retention_days) update the\nDecisionType row without bumping the version.",
        "operationId": "update_decision_type_api_v1_decision_types__decision_type_id__put",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionTypeUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionTypeResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "decision-types"
        ],
        "summary": "Delete Decision Type",
        "description": "Soft-delete a decision type.\n\nSets ``deleted_at`` so the row is excluded from all queries.\nAssociated data (versions, examples, policies, logs) is preserved\nfor audit purposes.",
        "operationId": "delete_decision_type_api_v1_decision_types__decision_type_id__delete",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/versions": {
      "get": {
        "tags": [
          "decision-types"
        ],
        "summary": "List Versions",
        "description": "List all versions for a decision type.",
        "operationId": "list_versions_api_v1_decision_types__decision_type_id__versions_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DecisionTypeVersionResponse"
                  },
                  "title": "Response List Versions Api V1 Decision Types  Decision Type Id  Versions Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/versions/{version_id}": {
      "get": {
        "tags": [
          "decision-types"
        ],
        "summary": "Get Version",
        "description": "Get a specific version of a decision type.",
        "operationId": "get_version_api_v1_decision_types__decision_type_id__versions__version_id__get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "version_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Version Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionTypeVersionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decide": {
      "post": {
        "tags": [
          "decisions"
        ],
        "summary": "Decide",
        "description": "Make a single decision.",
        "operationId": "decide_api_v1_decide_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decide/batch": {
      "post": {
        "tags": [
          "decisions"
        ],
        "summary": "Decide Batch",
        "description": "Make up to 50 ordered decisions with per-item error reporting.\n\nItems retain the same sequential billing and quota semantics as individual\ndecisions. Warm classifier work is vectorized in bounded microbatches, then\neach item runs the authoritative pipeline in request order.\n\n``results`` always matches the request's order and length.  A failed item\nis ``null`` and has a corresponding entry in ``errors`` with the same\nzero-based index.  A null result is never a business decision and must not\nbe acted on; retry only errors whose ``retryable`` field is true.",
        "operationId": "decide_batch_api_v1_decide_batch_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchDecisionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchDecisionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/examples": {
      "post": {
        "tags": [
          "examples"
        ],
        "summary": "Upload Examples",
        "description": "Upload user-provided training examples.",
        "operationId": "upload_examples_api_v1_decision_types__decision_type_id__examples_post",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExampleBulkCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ExampleResponse"
                  },
                  "title": "Response Upload Examples Api V1 Decision Types  Decision Type Id  Examples Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "examples"
        ],
        "summary": "List Examples",
        "description": "List training examples with filtering and pagination.",
        "operationId": "list_examples_api_v1_decision_types__decision_type_id__examples_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Page Size"
            }
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by source: user, synthetic",
              "title": "Source"
            },
            "description": "Filter by source: user, synthetic"
          },
          {
            "name": "reviewed",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by reviewed status",
              "title": "Reviewed"
            },
            "description": "Filter by reviewed status"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response List Examples Api V1 Decision Types  Decision Type Id  Examples Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/examples/generate": {
      "post": {
        "tags": [
          "examples"
        ],
        "summary": "Generate Examples",
        "description": "Generate synthetic training examples using the teacher model.",
        "operationId": "generate_examples_api_v1_decision_types__decision_type_id__examples_generate_post",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateExamplesRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ExampleResponse"
                  },
                  "title": "Response Generate Examples Api V1 Decision Types  Decision Type Id  Examples Generate Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/examples/stats": {
      "get": {
        "tags": [
          "examples"
        ],
        "summary": "Get example statistics",
        "description": "Get a summary of training data distribution without paginating through all examples. Returns counts by source (user/synthetic), by decision option, and totals.",
        "operationId": "get_example_stats_api_v1_decision_types__decision_type_id__examples_stats_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExampleStats"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/examples/{example_id}": {
      "delete": {
        "tags": [
          "examples"
        ],
        "summary": "Delete Example",
        "description": "Delete a single training example.",
        "operationId": "delete_example_api_v1_decision_types__decision_type_id__examples__example_id__delete",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "example_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Example Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/train": {
      "post": {
        "tags": [
          "training"
        ],
        "summary": "Trigger model training",
        "description": "Start training an ML policy for a decision type. Accepts optional quality-gate, augmentation, and tuning settings. Every request runs the complete task-specific pipeline. Returns 202 after Cloud Run accepts the job. If dispatch fails, returns 503 with the durable policy ID and status. Poll GET /policies/{policy_id} for subsequent status.\n\n**Quality gate:** Set `target_f1` to auto-deploy only when the target is met. If the target is not met, the policy stays in 'trained' status for manual review.\n\nOmit the request body to use full-pipeline defaults with no quality gate.",
        "operationId": "trigger_training_api_v1_decision_types__decision_type_id__train_post",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TrainingConfig"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Config"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "503": {
            "description": "Training could not be dispatched; the response identifies the durable terminal policy."
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/training-readiness": {
      "get": {
        "tags": [
          "training"
        ],
        "summary": "Check training readiness",
        "description": "Check whether a decision type has enough labelled examples to start training. Returns per-option counts and any issues that need to be addressed.",
        "operationId": "get_training_readiness_api_v1_decision_types__decision_type_id__training_readiness_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrainingReadiness"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/policies": {
      "get": {
        "tags": [
          "training"
        ],
        "summary": "List policies",
        "description": "List all policies for a decision type, ordered by creation date (newest first). Includes status, summary metrics, and quality gate status.",
        "operationId": "list_policies_api_v1_decision_types__decision_type_id__policies_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PolicySummary"
                  },
                  "title": "Response List Policies Api V1 Decision Types  Decision Type Id  Policies Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/policies/{policy_id}": {
      "get": {
        "tags": [
          "training"
        ],
        "summary": "Get policy detail",
        "description": "Get full detail for a specific policy, including rich metrics (per-class breakdown, confusion matrix, escalation estimate, latency estimates) and the training configuration that was used.\n\nIncludes stale training detection: an attempt with a dead heartbeat is fenced as 'stopping' until its exact Cloud Run execution is confirmed terminal, while a pre-start job retains the longer lifecycle allowance.",
        "operationId": "get_policy_api_v1_decision_types__decision_type_id__policies__policy_id__get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Policy Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/policies/{policy_id}/deploy": {
      "post": {
        "tags": [
          "training"
        ],
        "summary": "Deploy a policy",
        "description": "Deploy a policy (set as active for inference). Deactivates all other policies for the same decision type. Only policies with status 'trained' or 'deployed' can be deployed.",
        "operationId": "deploy_policy_api_v1_decision_types__decision_type_id__policies__policy_id__deploy_post",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Policy Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/policies/{policy_id}/cancel": {
      "post": {
        "tags": [
          "training"
        ],
        "summary": "Cancel a training job",
        "description": "Cancel a training job that is currently in progress. Durably fences the worker as 'cancelling', requests cancellation of this policy's exact Cloud Run execution, then marks it 'cancelled' only after Cloud Run confirms the stop operation. Policies already in 'cancelling' can be polled/retried safely.",
        "operationId": "cancel_training_api_v1_decision_types__decision_type_id__policies__policy_id__cancel_post",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Policy Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/policies/{policy_id}/progress": {
      "get": {
        "tags": [
          "training"
        ],
        "summary": "Get training progress",
        "description": "Get real-time training progress for a policy. Returns the current\ntraining stage, progress percentage, elapsed time, durable attempt\nhistory, and completed stages. Runtime-dependent completion times\nare not presented as a fixed estimate.\n\nOptimised for polling: reads from Redis (sub-1ms) with a database\nfallback. Poll every 3-5 seconds while status is 'training',\n'stopping', or 'cancelling'. A 'stopping' policy retains its\norganisation slot until the exact stale execution is confirmed\nterminal. Polling also reconciles a dead worker heartbeat.\n\nWhen training is complete (status is 'trained', 'deployed', or\n'cancelled') or has failed, returns the durable terminal state.",
        "operationId": "get_policy_progress_api_v1_decision_types__decision_type_id__policies__policy_id__progress_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Policy Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrainingProgressResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/logs": {
      "get": {
        "tags": [
          "logs"
        ],
        "summary": "Query Logs",
        "description": "Query decision logs with filtering and pagination.",
        "operationId": "query_logs_api_v1_decision_types__decision_type_id__logs_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Page Size"
            }
          },
          {
            "name": "decision",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by decision value",
              "title": "Decision"
            },
            "description": "Filter by decision value"
          },
          {
            "name": "escalated",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by escalation status",
              "title": "Escalated"
            },
            "description": "Filter by escalation status"
          },
          {
            "name": "min_confidence",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number",
                  "maximum": 1.0,
                  "minimum": 0.0
                },
                {
                  "type": "null"
                }
              ],
              "description": "Minimum confidence",
              "title": "Min Confidence"
            },
            "description": "Minimum confidence"
          },
          {
            "name": "max_confidence",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number",
                  "maximum": 1.0,
                  "minimum": 0.0
                },
                {
                  "type": "null"
                }
              ],
              "description": "Maximum confidence",
              "title": "Max Confidence"
            },
            "description": "Maximum confidence"
          },
          {
            "name": "start_time",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter logs after this time (ISO 8601)",
              "title": "Start Time"
            },
            "description": "Filter logs after this time (ISO 8601)"
          },
          {
            "name": "end_time",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter logs before this time (ISO 8601)",
              "title": "End Time"
            },
            "description": "Filter logs before this time (ISO 8601)"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Query Logs Api V1 Decision Types  Decision Type Id  Logs Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/logs/export": {
      "get": {
        "tags": [
          "logs"
        ],
        "summary": "Export Logs",
        "description": "Export decision logs as JSON or CSV.\n\nStreams results for efficient handling of large datasets.",
        "operationId": "export_logs_api_v1_decision_types__decision_type_id__logs_export_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ExportFormat",
              "description": "Export format: json or csv",
              "default": "json"
            },
            "description": "Export format: json or csv"
          },
          {
            "name": "decision",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by decision value",
              "title": "Decision"
            },
            "description": "Filter by decision value"
          },
          {
            "name": "escalated",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by escalation status",
              "title": "Escalated"
            },
            "description": "Filter by escalation status"
          },
          {
            "name": "min_confidence",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number",
                  "maximum": 1.0,
                  "minimum": 0.0
                },
                {
                  "type": "null"
                }
              ],
              "title": "Min Confidence"
            }
          },
          {
            "name": "max_confidence",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number",
                  "maximum": 1.0,
                  "minimum": 0.0
                },
                {
                  "type": "null"
                }
              ],
              "title": "Max Confidence"
            }
          },
          {
            "name": "start_time",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter logs after this time",
              "title": "Start Time"
            },
            "description": "Filter logs after this time"
          },
          {
            "name": "end_time",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter logs before this time",
              "title": "End Time"
            },
            "description": "Filter logs before this time"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/metrics": {
      "get": {
        "tags": [
          "logs"
        ],
        "summary": "Get Metrics",
        "description": "Get aggregated metrics for the last 24 hours.\n\nReturns total_decisions, avg_confidence, avg_latency_ms,\nescalation_rate, and decision_distribution.",
        "operationId": "get_metrics_api_v1_decision_types__decision_type_id__metrics_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Get Metrics Api V1 Decision Types  Decision Type Id  Metrics Get"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/decision-types/{decision_type_id}/export": {
      "get": {
        "tags": [
          "export"
        ],
        "summary": "Export Edge Bundle",
        "description": "Export the active policy as a standalone edge bundle (ZIP).\n\nReturns a ZIP file containing the ONNX model, feature config,\nCEL rules, and metadata.  The bundle can be loaded with\n``EdgePredictor.from_bundle()`` for offline inference.",
        "operationId": "export_edge_bundle_api_v1_decision_types__decision_type_id__export_get",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/metrics": {
      "get": {
        "tags": [
          "metrics"
        ],
        "summary": "Get Org Metrics",
        "description": "Org-level aggregate metrics for the last 24 hours.\n\nReturns total_decisions, avg_latency_ms, active_types,\nsuccess_rate, decision_distribution, and recent_decisions.",
        "operationId": "get_org_metrics_api_v1_metrics_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Get Org Metrics Api V1 Metrics Get"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models": {
      "get": {
        "tags": [
          "models"
        ],
        "summary": "Get Models Overview",
        "description": "List durable and local serving state for every owned decision type.",
        "operationId": "get_models_overview_api_v1_models_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelServingOverview"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/load": {
      "post": {
        "tags": [
          "models"
        ],
        "summary": "Load Model",
        "description": "Load a deployed model and opt into fleet-wide keep-warm coverage.\n\nThe first fixed one-hour window is charged immediately for paid orgs;\ntrial and demo organizations remain exempt.",
        "operationId": "load_model_api_v1_models_load_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoadModelRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelActionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/unload": {
      "post": {
        "tags": [
          "models"
        ],
        "summary": "Unload Model",
        "description": "Durably opt out and unload the model across every instance.",
        "operationId": "unload_model_api_v1_models_unload_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnloadModelRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelActionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{decision_type_id}/warmup": {
      "post": {
        "tags": [
          "models"
        ],
        "summary": "Warmup Model",
        "description": "Warm up a loaded model with a dummy inference pass.",
        "operationId": "warmup_model_api_v1_models__decision_type_id__warmup_post",
        "parameters": [
          {
            "name": "decision_type_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Decision Type Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelActionResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AugmentationStats": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Augmentation outcome: 'succeeded', 'partial', 'failed', or 'skipped'."
          },
          "original_count": {
            "type": "integer",
            "title": "Original Count",
            "description": "Number of original (non-augmented) examples."
          },
          "augmented_count": {
            "type": "integer",
            "title": "Augmented Count",
            "description": "Number of new examples generated.",
            "default": 0
          },
          "target_size": {
            "type": "integer",
            "title": "Target Size",
            "description": "Configured target dataset size."
          },
          "failure_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Failure Reason",
            "description": "Error message if augmentation failed."
          },
          "per_class_counts": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "integer"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Per Class Counts",
            "description": "Per-class example counts after augmentation."
          }
        },
        "type": "object",
        "required": [
          "status",
          "original_count",
          "target_size"
        ],
        "title": "AugmentationStats",
        "description": "Augmentation outcome reported in training metrics."
      },
      "AutoGenerationStats": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "'succeeded', 'partial', or 'skipped'."
          },
          "generated_count": {
            "type": "integer",
            "title": "Generated Count",
            "description": "Number of examples auto-generated.",
            "default": 0
          },
          "original_count": {
            "type": "integer",
            "title": "Original Count",
            "description": "Original example count before auto-generation."
          },
          "minimum_required": {
            "type": "integer",
            "title": "Minimum Required",
            "description": "Minimum total examples required for reliable evaluation."
          }
        },
        "type": "object",
        "required": [
          "status",
          "original_count",
          "minimum_required"
        ],
        "title": "AutoGenerationStats",
        "description": "Auto-generation outcome when the dataset was below the minimum for reliable evaluation."
      },
      "BatchDecisionError": {
        "properties": {
          "index": {
            "type": "integer",
            "maximum": 49.0,
            "minimum": 0.0,
            "title": "Index",
            "description": "Zero-based request item index"
          },
          "decision_type": {
            "type": "string",
            "title": "Decision Type",
            "description": "Decision type requested by the item"
          },
          "code": {
            "type": "string",
            "title": "Code",
            "description": "Stable machine-readable error code"
          },
          "message": {
            "type": "string",
            "title": "Message",
            "description": "Safe human-readable error message"
          },
          "status_code": {
            "type": "integer",
            "maximum": 599.0,
            "minimum": 400.0,
            "title": "Status Code",
            "description": "HTTP-equivalent status for this individual item"
          },
          "retryable": {
            "type": "boolean",
            "title": "Retryable",
            "description": "Whether retrying the item may succeed"
          },
          "request_id": {
            "type": "string",
            "title": "Request Id",
            "description": "Correlation ID for this individual item"
          }
        },
        "type": "object",
        "required": [
          "index",
          "decision_type",
          "code",
          "message",
          "status_code",
          "retryable",
          "request_id"
        ],
        "title": "BatchDecisionError",
        "description": "A non-decision result for one failed batch item."
      },
      "BatchDecisionRequest": {
        "properties": {
          "decisions": {
            "items": {
              "$ref": "#/components/schemas/DecisionRequest"
            },
            "type": "array",
            "maxItems": 50,
            "minItems": 1,
            "title": "Decisions",
            "description": "List of decision requests to evaluate"
          }
        },
        "type": "object",
        "required": [
          "decisions"
        ],
        "title": "BatchDecisionRequest",
        "description": "Batch of decision requests (max 50).\n\nAccepts either the canonical ``{\"decisions\": [...]}`` envelope or a\nbare JSON array ``[{...}, ...]`` for convenience."
      },
      "BatchDecisionResponse": {
        "properties": {
          "results": {
            "items": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/DecisionResponse"
                },
                {
                  "type": "null"
                }
              ]
            },
            "type": "array",
            "maxItems": 50,
            "title": "Results",
            "description": "Results in request order; null when the corresponding item failed"
          },
          "errors": {
            "items": {
              "$ref": "#/components/schemas/BatchDecisionError"
            },
            "type": "array",
            "maxItems": 50,
            "title": "Errors",
            "description": "Explicit errors for failed items, keyed by request index"
          }
        },
        "type": "object",
        "required": [
          "results"
        ],
        "title": "BatchDecisionResponse",
        "description": "Ordered batch results with explicit per-item failures.\n\n``results`` always has the same length and ordering as the request.  A\nfailed item is represented by ``None`` at its original position and a\ncorresponding entry in ``errors``.  Successful-only responses retain the\noriginal response shape, with ``errors`` added as an empty list."
      },
      "CompletedStage": {
        "properties": {
          "stage": {
            "type": "string",
            "title": "Stage",
            "description": "Stage identifier (e.g. 'preparing_data')."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable stage name."
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "title": "Completed At",
            "description": "When this stage finished."
          }
        },
        "type": "object",
        "required": [
          "stage",
          "name",
          "completed_at"
        ],
        "title": "CompletedStage",
        "description": "A training stage that has been completed."
      },
      "ConfidenceThresholds": {
        "properties": {
          "per_option": {
            "additionalProperties": {
              "type": "number"
            },
            "type": "object",
            "title": "Per Option",
            "description": "Minimum confidence required per decision option"
          },
          "escalate_below": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Escalate Below",
            "description": "Escalate if best confidence falls below this value",
            "default": 0.7
          }
        },
        "type": "object",
        "title": "ConfidenceThresholds",
        "description": "Per-option confidence thresholds and escalation floor."
      },
      "CreditBalanceResponse": {
        "properties": {
          "credits_remaining": {
            "type": "integer",
            "title": "Credits Remaining",
            "description": "Credits available this period"
          },
          "credits_total": {
            "type": "integer",
            "title": "Credits Total",
            "description": "Total credit allocation this period"
          },
          "percentage_used": {
            "type": "number",
            "title": "Percentage Used",
            "description": "Percentage of credits consumed"
          },
          "plan_tier": {
            "type": "string",
            "title": "Plan Tier",
            "description": "Current subscription tier"
          },
          "resets_at": {
            "type": "string",
            "title": "Resets At",
            "description": "ISO timestamp when credits reset"
          },
          "decisions_remaining": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Decisions Remaining",
            "description": "Decisions remaining (trial only, null for paid tiers)"
          },
          "max_decisions": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Max Decisions",
            "description": "Lifetime decision limit (trial only, null for unlimited)"
          }
        },
        "type": "object",
        "required": [
          "credits_remaining",
          "credits_total",
          "percentage_used",
          "plan_tier",
          "resets_at"
        ],
        "title": "CreditBalanceResponse",
        "description": "Current credit balance for the organisation."
      },
      "CreditUsageResponse": {
        "properties": {
          "events": {
            "items": {
              "$ref": "#/components/schemas/UsageEventItem"
            },
            "type": "array",
            "title": "Events"
          },
          "total": {
            "type": "integer",
            "title": "Total"
          },
          "period_start": {
            "type": "string",
            "title": "Period Start"
          },
          "summary": {
            "$ref": "#/components/schemas/UsageSummary"
          }
        },
        "type": "object",
        "required": [
          "events",
          "total",
          "period_start",
          "summary"
        ],
        "title": "CreditUsageResponse",
        "description": "Paginated usage history with summary."
      },
      "DecisionRequest": {
        "properties": {
          "decision_type": {
            "type": "string",
            "title": "Decision Type",
            "description": "Name of the decision type to evaluate"
          },
          "input": {
            "additionalProperties": true,
            "type": "object",
            "title": "Input",
            "description": "Arbitrary input payload matching the decision type's schema"
          },
          "latency_budget_ms": {
            "anyOf": [
              {
                "type": "number",
                "exclusiveMinimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Latency Budget Ms",
            "description": "Optional latency budget in milliseconds"
          }
        },
        "type": "object",
        "required": [
          "decision_type",
          "input"
        ],
        "title": "DecisionRequest",
        "description": "Single decision request payload.\n\nThe ``decision_type`` field accepts the type **name** (not UUID).\nCommon aliases ``type`` and ``decision_type_name`` are also accepted."
      },
      "DecisionResponse": {
        "properties": {
          "decision": {
            "type": "string",
            "title": "Decision",
            "description": "The chosen decision option"
          },
          "confidence": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Confidence",
            "description": "Model confidence"
          },
          "reason_codes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Reason Codes",
            "description": "Reason codes explaining the decision"
          },
          "escalate": {
            "type": "boolean",
            "title": "Escalate",
            "description": "Whether the decision should be escalated to a human",
            "default": false
          },
          "fallback_used": {
            "type": "boolean",
            "title": "Fallback Used",
            "description": "Whether a fallback strategy was used",
            "default": false
          },
          "rules_triggered": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Rules Triggered",
            "description": "Names of hard rules that fired"
          },
          "latency_ms": {
            "type": "number",
            "title": "Latency Ms",
            "description": "End-to-end latency in milliseconds"
          },
          "policy_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Policy Version",
            "description": "Version identifier of the policy used"
          },
          "class_probabilities": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "number"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Class Probabilities",
            "description": "Per-class probability scores from the ML classifier"
          },
          "explanation": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Explanation",
            "description": "Human-readable explanation of the decision"
          },
          "request_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Request Id",
            "description": "Unique identifier for this decision request"
          },
          "stage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stage",
            "description": "Pipeline stage that produced the decision (rules, classifier, escalation, fallback)"
          }
        },
        "type": "object",
        "required": [
          "decision",
          "confidence",
          "latency_ms"
        ],
        "title": "DecisionResponse",
        "description": "Single decision response payload."
      },
      "DecisionTypeCreate": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 256,
            "minLength": 1,
            "title": "Name"
          },
          "description": {
            "type": "string",
            "title": "Description",
            "default": ""
          },
          "options": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 50,
            "minItems": 2,
            "title": "Options",
            "description": "At least two decision options"
          },
          "reason_codes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 50,
            "title": "Reason Codes"
          },
          "rules": {
            "items": {
              "$ref": "#/components/schemas/RuleDefinition"
            },
            "type": "array",
            "maxItems": 100,
            "title": "Rules"
          },
          "confidence_thresholds": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ConfidenceThresholds"
              },
              {
                "type": "null"
              }
            ]
          },
          "input_schema": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Input Schema",
            "description": "Optional JSON Schema describing expected input shape"
          },
          "escalation_policy": {
            "additionalProperties": true,
            "type": "object",
            "title": "Escalation Policy",
            "description": "Live LLM escalation policy. New decision types default to classifier-only operation unless explicitly enabled."
          },
          "pii_fields": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 50,
            "title": "Pii Fields"
          },
          "retention_days": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Retention Days"
          },
          "fallback_option": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Fallback Option",
            "description": "Decision returned when no stage can produce a result. Must be one of the defined options. Defaults to the first option."
          }
        },
        "type": "object",
        "required": [
          "name",
          "options"
        ],
        "title": "DecisionTypeCreate",
        "description": "Payload for creating a new decision type."
      },
      "DecisionTypeResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "active_version": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DecisionTypeVersionResponse"
              },
              {
                "type": "null"
              }
            ]
          },
          "pii_fields": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Pii Fields",
            "default": []
          },
          "retention_days": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Retention Days"
          },
          "fallback_option": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fallback Option"
          },
          "model_deployed": {
            "type": "boolean",
            "title": "Model Deployed",
            "description": "Whether a trained model is deployed and ready for /decide calls.",
            "default": false
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "title": "Updated At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "created_at",
          "updated_at"
        ],
        "title": "DecisionTypeResponse",
        "description": "Serialised representation of a DecisionType with its active version."
      },
      "DecisionTypeUpdate": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 256,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "options": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array",
                "maxItems": 50,
                "minItems": 2
              },
              {
                "type": "null"
              }
            ],
            "title": "Options"
          },
          "reason_codes": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array",
                "maxItems": 50
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason Codes"
          },
          "rules": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/RuleDefinition"
                },
                "type": "array",
                "maxItems": 100
              },
              {
                "type": "null"
              }
            ],
            "title": "Rules"
          },
          "confidence_thresholds": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ConfidenceThresholds"
              },
              {
                "type": "null"
              }
            ]
          },
          "input_schema": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Input Schema"
          },
          "escalation_policy": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Escalation Policy"
          },
          "pii_fields": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array",
                "maxItems": 50
              },
              {
                "type": "null"
              }
            ],
            "title": "Pii Fields"
          },
          "retention_days": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Retention Days"
          },
          "fallback_option": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fallback Option"
          }
        },
        "type": "object",
        "title": "DecisionTypeUpdate",
        "description": "Payload for updating a decision type (all fields optional)."
      },
      "DecisionTypeVersionResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "version_number": {
            "type": "integer",
            "title": "Version Number"
          },
          "options": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Options"
          },
          "reason_codes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Reason Codes"
          },
          "hard_rules": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Hard Rules"
          },
          "input_schema": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Input Schema"
          },
          "confidence_thresholds": {
            "additionalProperties": true,
            "type": "object",
            "title": "Confidence Thresholds"
          },
          "escalation_policy": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Escalation Policy"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "version_number",
          "options",
          "reason_codes",
          "hard_rules",
          "confidence_thresholds",
          "created_at"
        ],
        "title": "DecisionTypeVersionResponse",
        "description": "Serialised representation of a DecisionTypeVersion."
      },
      "ExampleBulkCreate": {
        "properties": {
          "examples": {
            "items": {
              "$ref": "#/components/schemas/ExampleCreate"
            },
            "type": "array",
            "maxItems": 500,
            "minItems": 1,
            "title": "Examples",
            "description": "List of examples to create"
          }
        },
        "type": "object",
        "required": [
          "examples"
        ],
        "title": "ExampleBulkCreate",
        "description": "Payload for bulk-creating training examples.\n\nAccepts either the canonical ``{\"examples\": [...]}`` envelope or a\nbare JSON array ``[{...}, ...]`` for convenience.  The latter is\nsilently wrapped before validation."
      },
      "ExampleCreate": {
        "properties": {
          "input_payload": {
            "additionalProperties": true,
            "type": "object",
            "title": "Input Payload",
            "description": "The input that was evaluated"
          },
          "expected_decision": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Expected Decision",
            "description": "The expected/labelled decision"
          },
          "confidence": {
            "anyOf": [
              {
                "type": "number",
                "maximum": 1.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Confidence",
            "description": "Confidence of the label"
          },
          "reason_codes": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array",
                "maxItems": 50
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason Codes",
            "description": "Reason codes associated with the example"
          }
        },
        "type": "object",
        "required": [
          "input_payload"
        ],
        "title": "ExampleCreate",
        "description": "Payload for creating a single training example.\n\nAccepts both canonical field names (``input_payload``,\n``expected_decision``, ``reason_codes``) and the shorter aliases\n(``input``, ``decision``, ``reason_code``) for developer convenience."
      },
      "ExampleResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "input_payload": {
            "additionalProperties": true,
            "type": "object",
            "title": "Input Payload"
          },
          "expected_decision": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expected Decision"
          },
          "confidence": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Confidence"
          },
          "reason_codes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Reason Codes"
          },
          "source": {
            "type": "string",
            "title": "Source"
          },
          "reviewed": {
            "type": "boolean",
            "title": "Reviewed"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "input_payload",
          "reason_codes",
          "source",
          "reviewed",
          "created_at"
        ],
        "title": "ExampleResponse",
        "description": "Serialised representation of a DecisionExample."
      },
      "ExampleStats": {
        "properties": {
          "total": {
            "type": "integer",
            "title": "Total",
            "description": "Total example count."
          },
          "labelled": {
            "type": "integer",
            "title": "Labelled",
            "description": "Examples with a non-null expected_decision."
          },
          "unlabelled": {
            "type": "integer",
            "title": "Unlabelled",
            "description": "Examples without an expected_decision."
          },
          "by_source": {
            "additionalProperties": {
              "type": "integer"
            },
            "type": "object",
            "title": "By Source",
            "description": "Count by source: user, synthetic, augmented."
          },
          "by_decision": {
            "additionalProperties": {
              "type": "integer"
            },
            "type": "object",
            "title": "By Decision",
            "description": "Count per decision option."
          },
          "options": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 50,
            "title": "Options",
            "description": "The decision type's configured options."
          },
          "max_allowed": {
            "type": "integer",
            "title": "Max Allowed",
            "description": "Maximum examples allowed per decision type.",
            "default": 5000
          }
        },
        "type": "object",
        "required": [
          "total",
          "labelled",
          "unlabelled",
          "by_source",
          "by_decision",
          "options"
        ],
        "title": "ExampleStats",
        "description": "Response for ``GET /examples/stats``.\n\nProvides a summary of training data distribution without\nrequiring the caller to paginate through all examples."
      },
      "ExportFormat": {
        "type": "string",
        "enum": [
          "json",
          "csv"
        ],
        "title": "ExportFormat",
        "description": "Supported log export formats."
      },
      "GenerateExamplesRequest": {
        "properties": {
          "count": {
            "type": "integer",
            "maximum": 50.0,
            "minimum": 1.0,
            "title": "Count",
            "description": "Number of synthetic examples to generate (1\u201350 per request)",
            "default": 50
          }
        },
        "type": "object",
        "title": "GenerateExamplesRequest",
        "description": "Request to generate synthetic training examples via LLM."
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "LoadModelRequest": {
        "properties": {
          "decision_type_id": {
            "type": "string",
            "title": "Decision Type Id",
            "description": "UUID of the decision type to load"
          }
        },
        "type": "object",
        "required": [
          "decision_type_id"
        ],
        "title": "LoadModelRequest",
        "description": "Request to load a model into memory."
      },
      "ModelActionResponse": {
        "properties": {
          "success": {
            "type": "boolean",
            "title": "Success"
          },
          "message": {
            "type": "string",
            "title": "Message"
          },
          "credits_charged": {
            "type": "integer",
            "title": "Credits Charged",
            "default": 0
          },
          "keep_warm": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Keep Warm"
          },
          "keep_warm_generation": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Keep Warm Generation"
          },
          "next_charge_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Charge At"
          }
        },
        "type": "object",
        "required": [
          "success",
          "message"
        ],
        "title": "ModelActionResponse",
        "description": "Response for model load/unload/warmup actions."
      },
      "ModelServingOverview": {
        "properties": {
          "models": {
            "items": {
              "$ref": "#/components/schemas/ModelStatusResponse"
            },
            "type": "array",
            "title": "Models"
          },
          "total_memory_mb": {
            "type": "number",
            "title": "Total Memory Mb"
          },
          "budget_memory_mb": {
            "type": "number",
            "title": "Budget Memory Mb"
          },
          "utilization_percent": {
            "type": "number",
            "title": "Utilization Percent"
          }
        },
        "type": "object",
        "required": [
          "models",
          "total_memory_mb",
          "budget_memory_mb",
          "utilization_percent"
        ],
        "title": "ModelServingOverview",
        "description": "Tenant-scoped serving state for every owned decision type."
      },
      "ModelStatusResponse": {
        "properties": {
          "decision_type_id": {
            "type": "string",
            "title": "Decision Type Id"
          },
          "is_loaded": {
            "type": "boolean",
            "title": "Is Loaded",
            "default": true
          },
          "memory_mb": {
            "type": "number",
            "title": "Memory Mb"
          },
          "loaded_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Loaded At"
          },
          "last_used_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used At"
          },
          "requests_served": {
            "type": "integer",
            "title": "Requests Served",
            "default": 0
          },
          "is_always_hot": {
            "type": "boolean",
            "title": "Is Always Hot",
            "default": false
          },
          "keep_warm": {
            "type": "boolean",
            "title": "Keep Warm",
            "default": false
          },
          "keep_warm_generation": {
            "type": "integer",
            "title": "Keep Warm Generation",
            "default": 0
          },
          "next_charge_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Charge At"
          }
        },
        "type": "object",
        "required": [
          "decision_type_id",
          "memory_mb"
        ],
        "title": "ModelStatusResponse",
        "description": "Status of a single loaded model."
      },
      "OperationSummary": {
        "properties": {
          "credits": {
            "type": "integer",
            "title": "Credits"
          },
          "count": {
            "type": "integer",
            "title": "Count"
          }
        },
        "type": "object",
        "required": [
          "credits",
          "count"
        ],
        "title": "OperationSummary",
        "description": "Aggregate stats for a single operation type."
      },
      "PolicyMetricsDetail": {
        "properties": {
          "accuracy": {
            "type": "number",
            "title": "Accuracy",
            "description": "Overall accuracy on the test set."
          },
          "macro_f1": {
            "type": "number",
            "title": "Macro F1",
            "description": "Macro-averaged F1 score."
          },
          "macro_precision": {
            "type": "number",
            "title": "Macro Precision",
            "description": "Macro-averaged precision."
          },
          "macro_recall": {
            "type": "number",
            "title": "Macro Recall",
            "description": "Macro-averaged recall."
          },
          "per_class": {
            "additionalProperties": {
              "additionalProperties": {
                "type": "number"
              },
              "type": "object"
            },
            "type": "object",
            "title": "Per Class",
            "description": "Per-class precision, recall, and F1."
          },
          "confusion_matrix": {
            "anyOf": [
              {
                "items": {
                  "items": {
                    "type": "integer"
                  },
                  "type": "array"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Confusion Matrix",
            "description": "Confusion matrix as a 2D array (rows=true, cols=predicted)."
          },
          "confusion_labels": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Confusion Labels",
            "description": "Class labels corresponding to confusion matrix rows/columns."
          },
          "train_size": {
            "type": "integer",
            "title": "Train Size",
            "description": "Number of training examples used."
          },
          "test_size": {
            "type": "integer",
            "title": "Test Size",
            "description": "Number of test examples used."
          },
          "feature_count": {
            "type": "integer",
            "title": "Feature Count",
            "description": "Number of features extracted."
          },
          "escalation_estimate": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Escalation Estimate",
            "description": "Estimated fraction of decisions that would escalate at the configured threshold."
          },
          "latency_estimate_p50_ms": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latency Estimate P50 Ms",
            "description": "Estimated p50 inference latency in milliseconds."
          },
          "latency_estimate_p95_ms": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latency Estimate P95 Ms",
            "description": "Estimated p95 inference latency in milliseconds."
          },
          "augmentation": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/AugmentationStats"
              },
              {
                "type": "null"
              }
            ],
            "description": "Augmentation outcome and statistics, if augmentation was configured."
          },
          "auto_generation": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/AutoGenerationStats"
              },
              {
                "type": "null"
              }
            ],
            "description": "Auto-generation stats when examples were generated to meet minimum test set size."
          }
        },
        "type": "object",
        "required": [
          "accuracy",
          "macro_f1",
          "macro_precision",
          "macro_recall",
          "train_size",
          "test_size",
          "feature_count"
        ],
        "title": "PolicyMetricsDetail",
        "description": "Rich metrics returned on policy detail and list endpoints."
      },
      "PolicyResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "decision_type_id": {
            "type": "string",
            "format": "uuid",
            "title": "Decision Type Id"
          },
          "version": {
            "type": "integer",
            "title": "Version"
          },
          "policy_type": {
            "type": "string",
            "title": "Policy Type",
            "description": "Policy type: 'ml_classifier' or 'rules_only'."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Training status. 'stopping' means Sparkient fenced a stale worker and is retaining its organisation slot until the exact Cloud Run execution is confirmed terminal; 'cancelling' is user-requested."
          },
          "deployed": {
            "type": "boolean",
            "title": "Deployed"
          },
          "auto_deployed": {
            "type": "boolean",
            "title": "Auto Deployed",
            "description": "True if the policy was auto-deployed by a quality gate.",
            "default": false
          },
          "training_config": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TrainingConfigResolved"
              },
              {
                "type": "null"
              }
            ],
            "description": "The resolved training configuration used for this policy."
          },
          "metrics": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PolicyMetricsDetail"
              },
              {
                "type": "null"
              }
            ],
            "description": "Training evaluation metrics. Null while training is in progress."
          },
          "quality_gate_met": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Quality Gate Met",
            "description": "Whether the target F1 was met. None if no target was set."
          },
          "target_f1": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Target F1",
            "description": "The target F1 that was set for this training run."
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "Lifecycle error when training failed, is stopping after a stale heartbeat, or was cancelled."
          },
          "current_attempt_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Current Attempt Id"
          },
          "execution_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Execution Name"
          },
          "last_heartbeat_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Heartbeat At"
          },
          "last_training_error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Training Error"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "decision_type_id",
          "version",
          "policy_type",
          "status",
          "deployed",
          "created_at"
        ],
        "title": "PolicyResponse",
        "description": "Full policy response with rich metrics and training config."
      },
      "PolicySummary": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "decision_type_id": {
            "type": "string",
            "format": "uuid",
            "title": "Decision Type Id"
          },
          "version": {
            "type": "integer",
            "title": "Version"
          },
          "policy_type": {
            "type": "string",
            "title": "Policy Type"
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Training status: 'training', 'stopping', 'cancelling', 'trained', 'deployed', 'failed', or 'cancelled'."
          },
          "deployed": {
            "type": "boolean",
            "title": "Deployed"
          },
          "auto_deployed": {
            "type": "boolean",
            "title": "Auto Deployed",
            "default": false
          },
          "accuracy": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Accuracy"
          },
          "macro_f1": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Macro F1"
          },
          "train_size": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Train Size"
          },
          "quality_gate_met": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Quality Gate Met"
          },
          "augmentation_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Augmentation Status",
            "description": "High-level augmentation outcome: 'succeeded', 'partial', 'failed', or 'skipped'."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "decision_type_id",
          "version",
          "policy_type",
          "status",
          "deployed",
          "created_at"
        ],
        "title": "PolicySummary",
        "description": "Compact policy for list endpoint."
      },
      "RuleDefinition": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Unique rule name"
          },
          "condition": {
            "type": "string",
            "title": "Condition",
            "description": "Expression evaluated against input"
          },
          "then": {
            "type": "string",
            "title": "Then",
            "description": "Decision to force when condition is true"
          },
          "reason_code": {
            "type": "string",
            "title": "Reason Code",
            "description": "Reason code attached when rule fires"
          },
          "priority": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Priority",
            "description": "Lower number = higher priority",
            "default": 10
          }
        },
        "type": "object",
        "required": [
          "name",
          "condition",
          "then",
          "reason_code"
        ],
        "title": "RuleDefinition",
        "description": "A single hard rule expressed as an expression condition."
      },
      "TrainingAttemptResponse": {
        "properties": {
          "attempt_id": {
            "type": "string",
            "format": "uuid",
            "title": "Attempt Id"
          },
          "attempt_number": {
            "type": "integer",
            "title": "Attempt Number"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "execution_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Execution Name"
          },
          "task_index": {
            "type": "integer",
            "title": "Task Index"
          },
          "task_attempt": {
            "type": "integer",
            "title": "Task Attempt"
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "title": "Started At"
          },
          "last_heartbeat_at": {
            "type": "string",
            "format": "date-time",
            "title": "Last Heartbeat At"
          },
          "completed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completed At"
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error"
          }
        },
        "type": "object",
        "required": [
          "attempt_id",
          "attempt_number",
          "status",
          "task_index",
          "task_attempt",
          "started_at",
          "last_heartbeat_at"
        ],
        "title": "TrainingAttemptResponse",
        "description": "Durable history entry for one concrete training worker."
      },
      "TrainingConfig": {
        "properties": {
          "target_f1": {
            "anyOf": [
              {
                "type": "number",
                "maximum": 1.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Target F1",
            "description": "Minimum macro-F1 required for auto-deployment. If set, the policy will only auto-deploy when this threshold is met. If None, no quality gate is applied."
          },
          "auto_deploy": {
            "type": "boolean",
            "title": "Auto Deploy",
            "description": "If True and target_f1 is met (or no target set), automatically deploy the policy after training completes.",
            "default": true
          },
          "augment": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Augment",
            "description": "Enable/disable data augmentation. None uses the full-pipeline default (enabled)."
          },
          "augment_target_size": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 5000.0,
                "minimum": 50.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Augment Target Size",
            "description": "Target total dataset size after augmentation (max 5,000). Default: options \u00d7 300 (e.g. 4 options \u2192 1,200). Higher values increase coverage and runtime but do not guarantee better held-out quality."
          },
          "auto_generate": {
            "type": "boolean",
            "title": "Auto Generate",
            "description": "Explicitly allow generation of extra synthetic examples when the submitted dataset is smaller than the evaluation target. Disabled by default; training never generates hidden data.",
            "default": false
          },
          "tune_hyperparams": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tune Hyperparams",
            "description": "Enable/disable automated HP tuning. None uses the full-pipeline default (enabled)."
          },
          "n_tuning_trials": {
            "type": "integer",
            "maximum": 100.0,
            "minimum": 5.0,
            "title": "N Tuning Trials",
            "description": "Number of hyperparameter tuning trials.",
            "default": 20
          },
          "escalation_threshold": {
            "type": "number",
            "maximum": 0.95,
            "minimum": 0.5,
            "title": "Escalation Threshold",
            "description": "Confidence threshold below which decisions escalate to the LLM fallback. Used for escalation rate estimation.",
            "default": 0.7
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "TrainingConfig",
        "description": "Training configuration sent as the request body to ``POST /train``.\n\nThe task-specific text and classifier pipeline is mandatory.  Callers may\nconfigure augmentation, tuning, and deployment around that complete\npipeline.\n\nExample::\n\n    {\n        \"target_f1\": 0.85,\n        \"auto_deploy\": true\n    }",
        "examples": [
          {
            "auto_deploy": true,
            "target_f1": 0.85
          },
          {
            "augment": false,
            "auto_generate": false,
            "tune_hyperparams": false
          },
          {
            "augment": true,
            "augment_target_size": 1500,
            "escalation_threshold": 0.75,
            "n_tuning_trials": 50,
            "target_f1": 0.8,
            "tune_hyperparams": true
          }
        ]
      },
      "TrainingConfigResolved": {
        "properties": {
          "augment": {
            "type": "boolean",
            "title": "Augment"
          },
          "augment_target_size": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Augment Target Size"
          },
          "auto_generate": {
            "type": "boolean",
            "title": "Auto Generate",
            "default": false
          },
          "tune_hyperparams": {
            "type": "boolean",
            "title": "Tune Hyperparams"
          },
          "n_tuning_trials": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "N Tuning Trials"
          },
          "target_f1": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Target F1"
          },
          "auto_deploy": {
            "type": "boolean",
            "title": "Auto Deploy"
          },
          "escalation_threshold": {
            "type": "number",
            "title": "Escalation Threshold"
          }
        },
        "type": "object",
        "required": [
          "augment",
          "augment_target_size",
          "tune_hyperparams",
          "n_tuning_trials",
          "target_f1",
          "auto_deploy",
          "escalation_threshold"
        ],
        "title": "TrainingConfigResolved",
        "description": "Fully resolved training config after applying pipeline defaults.\n\nStored on the ``DecisionPolicy`` record so we know exactly what\nsettings were used for each training run."
      },
      "TrainingProgressResponse": {
        "properties": {
          "policy_id": {
            "type": "string",
            "format": "uuid",
            "title": "Policy Id"
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Policy status: 'training', 'stopping', 'cancelling', 'trained', 'deployed', 'failed', or 'cancelled'."
          },
          "stage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stage",
            "description": "Current training stage identifier (null when complete or not started)."
          },
          "stage_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stage Name",
            "description": "Human-readable name of the current stage."
          },
          "stage_number": {
            "type": "integer",
            "title": "Stage Number",
            "description": "Current stage number (1-based).",
            "default": 0
          },
          "total_stages": {
            "type": "integer",
            "title": "Total Stages",
            "description": "Total number of stages in this training run.",
            "default": 0
          },
          "progress_percent": {
            "type": "integer",
            "maximum": 100.0,
            "minimum": 0.0,
            "title": "Progress Percent",
            "description": "Overall progress percentage (0-100).",
            "default": 0
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message",
            "description": "Human-readable description of what is currently happening."
          },
          "started_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Started At",
            "description": "When training began."
          },
          "elapsed_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Elapsed Seconds",
            "description": "Seconds elapsed since training started."
          },
          "duration_hint": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Duration Hint",
            "description": "Reserved for a future workload-grounded estimate. Currently null; Sparkient does not publish a fixed stage duration."
          },
          "completed_stages": {
            "items": {
              "$ref": "#/components/schemas/CompletedStage"
            },
            "type": "array",
            "title": "Completed Stages",
            "description": "Stages that have been completed, in order."
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "Lifecycle error when training failed, is stopping after a stale heartbeat, or was cancelled."
          },
          "attempt_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Attempt Id",
            "description": "Current durable worker-attempt ID used as the write fence."
          },
          "attempt_number": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Attempt Number"
          },
          "retry_count": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Retry Count",
            "default": 0
          },
          "execution_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Execution Name"
          },
          "task_index": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Task Index"
          },
          "task_attempt": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Task Attempt"
          },
          "attempt_started_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Attempt Started At"
          },
          "last_heartbeat_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Heartbeat At"
          },
          "estimated_completion_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Estimated Completion At",
            "description": "Null until a workload-grounded estimate is available."
          },
          "attempts": {
            "items": {
              "$ref": "#/components/schemas/TrainingAttemptResponse"
            },
            "type": "array",
            "title": "Attempts"
          }
        },
        "type": "object",
        "required": [
          "policy_id",
          "status"
        ],
        "title": "TrainingProgressResponse",
        "description": "Response for ``GET /policies/{id}/progress``.\n\nProvides real-time training progress information including the\ncurrent stage, progress percentage, elapsed time, and history of\ncompleted stages."
      },
      "TrainingReadiness": {
        "properties": {
          "ready": {
            "type": "boolean",
            "title": "Ready",
            "description": "True if all minimums are met and training can proceed."
          },
          "total_examples": {
            "type": "integer",
            "title": "Total Examples",
            "description": "Total number of examples (labelled + unlabelled)."
          },
          "labelled_examples": {
            "type": "integer",
            "title": "Labelled Examples",
            "description": "Number of examples with a non-null expected_decision."
          },
          "per_option": {
            "additionalProperties": {
              "type": "integer"
            },
            "type": "object",
            "title": "Per Option",
            "description": "Count of labelled examples per decision option."
          },
          "options": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 50,
            "title": "Options",
            "description": "The decision type's configured options."
          },
          "min_total": {
            "type": "integer",
            "title": "Min Total",
            "description": "Minimum total labelled examples required.",
            "default": 38
          },
          "min_per_option": {
            "type": "integer",
            "title": "Min Per Option",
            "description": "Minimum labelled examples required for every option.",
            "default": 38
          },
          "issues": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 50,
            "title": "Issues",
            "description": "Human-readable list of issues preventing training."
          }
        },
        "type": "object",
        "required": [
          "ready",
          "total_examples",
          "labelled_examples",
          "per_option",
          "options"
        ],
        "title": "TrainingReadiness",
        "description": "Response for ``GET /training-readiness``.\n\nTells the caller whether a decision type has enough training data\nand what issues (if any) need to be fixed before training."
      },
      "UnloadModelRequest": {
        "properties": {
          "decision_type_id": {
            "type": "string",
            "title": "Decision Type Id",
            "description": "UUID of the decision type to unload"
          }
        },
        "type": "object",
        "required": [
          "decision_type_id"
        ],
        "title": "UnloadModelRequest",
        "description": "Request to unload a model from memory."
      },
      "UsageEventItem": {
        "properties": {
          "operation": {
            "type": "string",
            "title": "Operation"
          },
          "credits_deducted": {
            "type": "integer",
            "title": "Credits Deducted"
          },
          "timestamp": {
            "type": "string",
            "title": "Timestamp"
          }
        },
        "type": "object",
        "required": [
          "operation",
          "credits_deducted",
          "timestamp"
        ],
        "title": "UsageEventItem",
        "description": "A single credit-consuming event."
      },
      "UsageSummary": {
        "properties": {
          "total_credits_used": {
            "type": "integer",
            "title": "Total Credits Used"
          },
          "by_operation": {
            "additionalProperties": {
              "$ref": "#/components/schemas/OperationSummary"
            },
            "type": "object",
            "title": "By Operation"
          }
        },
        "type": "object",
        "required": [
          "total_credits_used",
          "by_operation"
        ],
        "title": "UsageSummary",
        "description": "Aggregated usage summary for the period."
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    }
  },
  "tags": [
    {
      "name": "decisions",
      "description": "Make structured decisions against deployed policies. The compiled stage targets under 100ms; optional escalation is model-dependent."
    },
    {
      "name": "decision-types",
      "description": "CRUD for decision types. A decision type defines what you're deciding (options, rules, input schema)."
    },
    {
      "name": "examples",
      "description": "Manage training examples. Upload your own data, generate synthetic examples, or view class balance statistics."
    },
    {
      "name": "training",
      "description": "Train full-pipeline ML policies from examples. Configure quality gates (target F1 with auto-deploy), augmentation, and HP tuning."
    },
    {
      "name": "logs",
      "description": "Query decision history with filters. Per-type metrics and aggregations."
    },
    {
      "name": "metrics",
      "description": "Organization-level aggregate statistics across all decision types."
    },
    {
      "name": "export",
      "description": "Export edge bundles (ONNX model + rules + config) for offline/on-device inference."
    },
    {
      "name": "auth",
      "description": "User profile and organization management."
    },
    {
      "name": "api-keys",
      "description": "API key lifecycle management. Create, list, and revoke API keys."
    },
    {
      "name": "billing",
      "description": "Stripe billing, usage metering, credit management, and subscription portal."
    }
  ]
}
