{
  "openapi": "3.1.0",
  "info": {
    "title": "Throndar Verification API",
    "version": "1.0.0",
    "summary": "Verify a Throndar answer and generate AI Provenance Records.",
    "description": "Public, no-auth, CORS-enabled, stateless endpoints for verifying a Throndar answer's post-quantum signature, turning a verified proof into an AI Provenance Record, and fetching the published keys.\n\nVerification runs against the public keys embedded in the proof bundle, so a caller never has to trust Throndar's servers at check time. Nothing is stored.\n\nHONEST FRAMING: a passing verdict attests an answer's ORIGIN and INTEGRITY (it came from Throndar, unaltered), NOT its factual ACCURACY. `signerRecognized:true` additionally confirms the signing key is one Throndar publishes. Algorithm names denote the public standards the primitives are based on (ML-DSA-87 / FIPS 204, ML-KEM-1024 / FIPS 203; Falcon / FN-DSA, FIPS 206 forthcoming), not a FIPS-140 / CMVP validation.",
    "contact": {
      "name": "Throndar",
      "url": "https://throndar.ai/developers"
    },
    "license": {
      "name": "See throndar.ai/terms",
      "url": "https://throndar.ai/terms"
    }
  },
  "servers": [
    {
      "url": "https://throndar.ai",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "verification",
      "description": "Check a proof bundle."
    },
    {
      "name": "evidence",
      "description": "Produce an AI Provenance Record."
    },
    {
      "name": "keys",
      "description": "Published public keys."
    },
    {
      "name": "inventory",
      "description": "Cryptographic Bill of Materials (CBOM)."
    },
    {
      "name": "transparency",
      "description": "Public append-only transparency ledger (RFC 6962)."
    }
  ],
  "paths": {
    "/api/v1/verify": {
      "post": {
        "tags": [
          "verification"
        ],
        "summary": "Verify a proof, transcript, or Autopilot run bundle",
        "description": "Runs the same verification the browser uses. `verdict.overallOk` means the embedded signatures verify against the embedded keys (INTEGRITY). `signerRecognized` means the signing key is a published Throndar key (ORIGIN) — only `signerRecognized:true` means \"produced by Throndar\". No network calls; nothing stored.",
        "operationId": "verifyBundle",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ProofBundle"
                  },
                  {
                    "$ref": "#/components/schemas/TranscriptBundle"
                  },
                  {
                    "$ref": "#/components/schemas/RunProofBundle"
                  },
                  {
                    "$ref": "#/components/schemas/ExportArchive"
                  },
                  {
                    "$ref": "#/components/schemas/SthBundle"
                  },
                  {
                    "$ref": "#/components/schemas/ConsistencyBundle"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The structured verdict.",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string"
                },
                "description": "*"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                },
                "example": {
                  "service": "Throndar",
                  "kind": "throndar-proof",
                  "created": 1782000000,
                  "verdict": {
                    "overallOk": true,
                    "checks": 1,
                    "receipt": {
                      "present": true,
                      "answerHashOk": true,
                      "sigOk": true,
                      "keyId": "0986d89fa3c74566",
                      "councilGrounded": true
                    },
                    "signerRecognized": true
                  },
                  "signerRecognized": true,
                  "disclaimer": "verdict.overallOk means the bundle's embedded signatures verify against its embedded keys (INTEGRITY). signerRecognized additionally confirms those signing keys are keys Throndar publishes (ORIGIN)..."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadJson"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "422": {
            "$ref": "#/components/responses/NotABundle"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "options": {
        "tags": [
          "verification"
        ],
        "summary": "CORS preflight",
        "operationId": "verifyPreflight",
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/api/v1/evidence": {
      "post": {
        "tags": [
          "evidence"
        ],
        "summary": "Generate an AI Provenance Record",
        "description": "Turns a proof bundle into an AI Provenance Record: the verified proof embedded as the trust root, a factual summary derived from verification, and the published EU-AI-Act obligation mapping. Factual evidence — never a declaration of conformity. A bundle that doesn't verify still returns a record that honestly reports `attested.signed:false`.",
        "operationId": "generateEvidenceRecord",
        "parameters": [
          {
            "name": "org",
            "in": "query",
            "required": false,
            "description": "Optional subject organisation stamped into the record (max 200 chars).",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ProofBundle"
                  },
                  {
                    "$ref": "#/components/schemas/RunProofBundle"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The AI Provenance Record (save the body as the .json artifact).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiProvenanceRecord"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadJson"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "422": {
            "$ref": "#/components/responses/NotABundle"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "options": {
        "tags": [
          "evidence"
        ],
        "summary": "CORS preflight",
        "operationId": "evidencePreflight",
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/api/provenance/pubkey": {
      "get": {
        "tags": [
          "keys"
        ],
        "summary": "Published answer-receipt public keys",
        "description": "The ML-DSA-87 public key(s) used to verify answer-provenance receipts. Returns an array so historical key_ids keep resolving across rotations. Cached one hour.",
        "operationId": "getPublicKeys",
        "responses": {
          "200": {
            "description": "The published keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PubkeysResponse"
                },
                "example": {
                  "algo": "ML-DSA-87",
                  "context": "throndar-provenance-v1",
                  "configured": true,
                  "keys": [
                    {
                      "key_id": "0986d89fa3c74566",
                      "public_key_hex": "…",
                      "context": "throndar-provenance-v1",
                      "algo": "ML-DSA-87"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/cbom": {
      "get": {
        "tags": [
          "inventory"
        ],
        "summary": "Cryptographic Bill of Materials",
        "description": "A public, machine-readable inventory of every cryptographic primitive Throndar relies on, mapped to its NIST standard, role, and status (CycloneDX-CBOM flavoured; TNO/AIVD/CWI PQC Migration Handbook §2.3.4). Algorithm names denote the public standards the primitives are based on — NOT a CMVP/FIPS-140 validation. ML-DSA-87 (FIPS 204) is the sole load-bearing signature; Falcon/FN-DSA (FIPS 206 draft) is a NON-authoritative diversity co-signature. Cached one hour.",
        "operationId": "getCbom",
        "responses": {
          "200": {
            "description": "The CBOM document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cbom"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/transparency/ledger": {
      "get": {
        "tags": [
          "transparency"
        ],
        "summary": "Current Signed Tree Head",
        "description": "The current Signed Tree Head of the append-only RFC 6962 Merkle log of every signed Throndar answer (hashes only, never content): tree size + Merkle root, with an ML-DSA-87 `signed_tree_head` (domain 'throndar-sth-v1'). Returns `{enabled:false}` when the ledger is off.",
        "operationId": "getLedgerSth",
        "responses": {
          "200": {
            "description": "The signed tree head.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LedgerSth"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Ledger temporarily unavailable."
          }
        }
      },
      "options": {
        "tags": [
          "transparency"
        ],
        "summary": "CORS preflight",
        "operationId": "ledgerPreflight",
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/api/transparency/ledger/inclusion": {
      "post": {
        "tags": [
          "transparency"
        ],
        "summary": "Prove an answer is in the ledger",
        "description": "Returns the RFC 6962 inclusion (audit) path for an answer, which the CALLER re-verifies in-browser against the signed root — a '✓ included' verdict trusts the math, not the server. Supply one of `answer`, `answer_sha256`, or `leaf`; optionally pin `tree_size`.",
        "operationId": "ledgerInclusion",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InclusionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Inclusion result (found + proof, or found:false).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InclusionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadJson"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "422": {
            "description": "No usable answer/answer_sha256/leaf supplied."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Ledger temporarily unavailable."
          }
        }
      },
      "options": {
        "tags": [
          "transparency"
        ],
        "summary": "CORS preflight",
        "operationId": "inclusionPreflight",
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/api/transparency/ledger/consistency": {
      "get": {
        "tags": [
          "transparency"
        ],
        "summary": "Append-only consistency proof",
        "description": "A consistency proof that the log at size `first` is an exact prefix of the log at size `second` (default: current) — i.e. the ledger only appended, never rewrote or deleted history. Re-verify in-browser.",
        "operationId": "ledgerConsistency",
        "parameters": [
          {
            "name": "first",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "second",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The consistency proof.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsistencyResponse"
                }
              }
            }
          },
          "422": {
            "description": "first/second out of range."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Ledger temporarily unavailable."
          }
        }
      },
      "options": {
        "tags": [
          "transparency"
        ],
        "summary": "CORS preflight",
        "operationId": "consistencyPreflight",
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/api/transparency/ledger/history": {
      "get": {
        "tags": [
          "transparency"
        ],
        "summary": "Signed-tree-head witness history",
        "description": "Recent Throndar-signed tree heads (the CT-style gossip record). `consistent:false` with `forked_sizes` would expose a split-view (two roots for one tree_size); `append_only_verified` recomputes each checkpoint against the live log.",
        "operationId": "ledgerHistory",
        "responses": {
          "200": {
            "description": "The witness history.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LedgerHistory"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "History temporarily unavailable."
          }
        }
      },
      "options": {
        "tags": [
          "transparency"
        ],
        "summary": "CORS preflight",
        "operationId": "historyPreflight",
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/api/v1/evidence-signer": {
      "get": {
        "summary": "Evidence Pack signer public keys",
        "description": "The pinned PUBLIC keys (ML-DSA-87, FIPS 204; hybrid leg SLH-DSA-SHA2-256f, FIPS 205) that sign paid Evidence Packs. Buyers cross-check the signer.pub.json delivered with their pack against this endpoint, then verify offline with @trelyan/verify-pqc. Key ids are SHA-256 fingerprints of the raw public keys. No auth; CORS-open.",
        "tags": [
          "verification"
        ],
        "responses": {
          "200": {
            "description": "Signer identity: alg, per-key publicKeyHex + fingerprint, verification instructions, and the self-attested (not a certification) notice.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string"
                    },
                    "issuer": {
                      "type": "string"
                    },
                    "alg": {
                      "type": "string"
                    },
                    "keys": {
                      "type": "object"
                    },
                    "verify": {
                      "type": "string"
                    },
                    "notice": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "BadJson": {
        "description": "Body is not valid JSON.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooLarge": {
        "description": "Payload over 2 MB.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotABundle": {
        "description": "Not a recognised Throndar bundle (or too many transcript turns).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Per-IP rate limit exceeded — honour the Retry-After header. Limits vary by endpoint: the v1 verify/evidence POSTs are ~40/min; the public read endpoints (pubkey, CBOM, ledger) are ~60–120/min.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      },
      "ReceiptEnvelope": {
        "type": "object",
        "description": "The signed answer receipt (ML-DSA-87 over a canonical core).",
        "properties": {
          "v": {
            "type": "integer"
          },
          "model": {
            "type": "string",
            "example": "throndar-council"
          },
          "answer_sha256": {
            "type": "string",
            "description": "SHA-256 (hex) of the exact answer text."
          },
          "governance_flag": {
            "type": "string",
            "example": "PASS"
          },
          "ts": {
            "type": "integer",
            "description": "Unix seconds the receipt was signed."
          },
          "council_grounded": {
            "type": "boolean",
            "description": "false ⇒ a single-model fallback (bound into the signature; only serialized when false)."
          },
          "sig": {
            "type": "string",
            "description": "hex signature"
          },
          "key_id": {
            "type": "string",
            "description": "hex thumbprint of the public key"
          },
          "context": {
            "type": "string",
            "example": "throndar-provenance-v1"
          },
          "algo": {
            "type": "string",
            "example": "ML-DSA-87"
          }
        },
        "required": [
          "v",
          "model",
          "answer_sha256",
          "ts",
          "sig",
          "key_id",
          "context",
          "algo"
        ]
      },
      "ReceiptKey": {
        "type": "object",
        "properties": {
          "key_id": {
            "type": "string"
          },
          "public_key_hex": {
            "type": "string"
          },
          "algo": {
            "type": "string"
          },
          "context": {
            "type": "string"
          }
        },
        "required": [
          "key_id",
          "public_key_hex",
          "algo",
          "context"
        ]
      },
      "ProofBundle": {
        "type": "object",
        "description": "A portable, self-verifying proof of one answer (the \"Download proof\" JSON).",
        "properties": {
          "v": {
            "type": "integer"
          },
          "kind": {
            "type": "string",
            "const": "throndar-proof"
          },
          "created": {
            "type": "integer"
          },
          "answer": {
            "type": "string",
            "description": "The exact signed answer text."
          },
          "receipt": {
            "$ref": "#/components/schemas/ReceiptEnvelope"
          },
          "receiptKey": {
            "$ref": "#/components/schemas/ReceiptKey"
          },
          "attestation": {
            "type": "object",
            "description": "Optional model-plane dual-signature (ML-DSA-87 + Falcon-1024)."
          },
          "bridgeKeys": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        },
        "required": [
          "kind",
          "answer"
        ]
      },
      "TranscriptBundle": {
        "type": "object",
        "description": "A whole-conversation proof: an ordered list of signed turns.",
        "properties": {
          "kind": {
            "type": "string",
            "const": "throndar-transcript"
          },
          "title": {
            "type": "string"
          },
          "turns": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "maxItems": 200
          }
        },
        "required": [
          "kind",
          "turns"
        ]
      },
      "ProofVerdict": {
        "type": "object",
        "properties": {
          "overallOk": {
            "type": "boolean",
            "description": "True only if every present layer verifies AND at least one layer was checked."
          },
          "checks": {
            "type": "integer"
          },
          "receipt": {
            "type": "object",
            "properties": {
              "present": {
                "type": "boolean"
              },
              "answerHashOk": {
                "type": "boolean"
              },
              "sigOk": {
                "type": "boolean"
              },
              "keyId": {
                "type": "string"
              },
              "councilGrounded": {
                "type": "boolean",
                "description": "false ⇒ single-model fallback (trustworthy only when sigOk)."
              }
            }
          },
          "bridge": {
            "type": "object",
            "properties": {
              "present": {
                "type": "boolean"
              },
              "primaryOk": {
                "type": "boolean"
              },
              "secondaryOk": {
                "type": "boolean"
              },
              "keyId": {
                "type": "string"
              }
            }
          },
          "signerRecognized": {
            "type": "boolean",
            "description": "Signing key matches a published Throndar key (ORIGIN)."
          }
        },
        "required": [
          "overallOk",
          "checks"
        ]
      },
      "VerifyResponse": {
        "type": "object",
        "properties": {
          "service": {
            "type": "string",
            "const": "Throndar"
          },
          "kind": {
            "type": "string"
          },
          "created": {
            "type": [
              "integer",
              "null"
            ]
          },
          "verdict": {
            "$ref": "#/components/schemas/ProofVerdict"
          },
          "signerRecognized": {
            "type": "boolean"
          },
          "disclaimer": {
            "type": "string"
          }
        },
        "required": [
          "service",
          "verdict",
          "signerRecognized",
          "disclaimer"
        ]
      },
      "AiProvenanceRecord": {
        "type": "object",
        "description": "A contextual wrapper around a signed proof: the trust root is the embedded `proof`; the summary is recomputable from it. Not a new signature, not a conformity declaration.",
        "properties": {
          "schema": {
            "type": "string",
            "const": "throndar-ai-provenance-record"
          },
          "schema_version": {
            "type": "integer",
            "const": 1
          },
          "generated": {
            "type": "integer"
          },
          "subject": {
            "type": "object",
            "properties": {
              "organisation": {
                "type": "string"
              }
            }
          },
          "attested": {
            "type": "object",
            "properties": {
              "signed": {
                "type": "boolean"
              },
              "signer_recognized": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "answer_sha256": {
                "type": "string"
              },
              "algorithms": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "governance_flag": {
                "type": "string"
              },
              "council_grounded": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "signed_at": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "receipt_key_id": {
                "type": "string"
              }
            }
          },
          "ai_act_support": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Published EU-AI-Act obligation mapping (illustrative, not a legal determination)."
          },
          "proof": {
            "$ref": "#/components/schemas/ProofBundle"
          },
          "verify_instructions": {
            "type": "string"
          },
          "disclaimer": {
            "type": "string"
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "schema",
          "schema_version",
          "generated",
          "attested",
          "proof",
          "disclaimer"
        ]
      },
      "PubkeysResponse": {
        "type": "object",
        "properties": {
          "algo": {
            "type": "string"
          },
          "context": {
            "type": "string"
          },
          "configured": {
            "type": "boolean"
          },
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReceiptKey"
            }
          },
          "slh_diversity": {
            "type": "object",
            "description": "Optional SLH-DSA-256f diversity public key (present only when enabled)."
          }
        },
        "required": [
          "algo",
          "context",
          "configured",
          "keys"
        ]
      },
      "Cbom": {
        "type": "object",
        "description": "CycloneDX-CBOM-flavoured cryptographic inventory. A transparency document, not a certification.",
        "properties": {
          "bomFormat": {
            "type": "string"
          },
          "specVersion": {
            "type": "string"
          },
          "metadata": {
            "type": "object"
          },
          "cryptography": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "standard": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "role": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                }
              }
            }
          },
          "posture": {
            "type": "object"
          },
          "disclaimer": {
            "type": "string"
          }
        },
        "required": [
          "bomFormat",
          "cryptography",
          "disclaimer"
        ]
      },
      "LedgerSth": {
        "type": "object",
        "description": "A Signed Tree Head (or {enabled:false} when the ledger is off).",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "log": {
            "type": "string",
            "example": "throndar-answers-v1"
          },
          "algo": {
            "type": "string",
            "example": "RFC6962-SHA256"
          },
          "leaf_hashing": {
            "type": "string"
          },
          "tree_size": {
            "type": "integer"
          },
          "root_hash": {
            "type": "string"
          },
          "signed_tree_head": {
            "type": [
              "object",
              "null"
            ],
            "description": "ML-DSA-87 signature over {log,tree_size,root_hash,timestamp} under 'throndar-sth-v1'."
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "enabled"
        ]
      },
      "InclusionRequest": {
        "type": "object",
        "description": "Supply exactly one of answer / answer_sha256 / leaf.",
        "properties": {
          "answer": {
            "type": "string"
          },
          "answer_sha256": {
            "type": "string",
            "description": "SHA-256 (hex) of the answer."
          },
          "leaf": {
            "type": "string",
            "description": "Precomputed Merkle leaf hash (hex)."
          },
          "tree_size": {
            "type": "integer",
            "description": "Optional: pin the proof to a specific tree size."
          }
        }
      },
      "InclusionResponse": {
        "type": "object",
        "properties": {
          "found": {
            "type": "boolean"
          },
          "leaf": {
            "type": "string"
          },
          "index": {
            "type": "integer"
          },
          "tree_size": {
            "type": "integer"
          },
          "root_hash": {
            "type": "string"
          },
          "proof": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "RFC 6962 inclusion (audit) path."
          }
        },
        "required": [
          "found"
        ]
      },
      "ConsistencyResponse": {
        "type": "object",
        "properties": {
          "first": {
            "type": "integer"
          },
          "second": {
            "type": "integer"
          },
          "old_root": {
            "type": "string"
          },
          "new_root": {
            "type": "string"
          },
          "proof": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "RFC 6962 consistency proof."
          }
        },
        "required": [
          "first",
          "second",
          "old_root",
          "new_root",
          "proof"
        ]
      },
      "LedgerHistory": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "consistent": {
            "type": "boolean",
            "description": "No split-view AND append-only verified server-side."
          },
          "forked_sizes": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "append_only_verified": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "inconsistent_sizes": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "count": {
            "type": "integer"
          },
          "checkpoints": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tree_size": {
                  "type": "integer"
                },
                "root_hash": {
                  "type": "string"
                },
                "signed": {
                  "type": "string"
                },
                "recorded": {
                  "type": "integer"
                }
              }
            }
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "enabled"
        ]
      },
      "RunProofBundle": {
        "type": "object",
        "description": "An Autopilot run EVIDENCE PACK — a portable, self-verifying proof of a whole guardrailed run (the \"Download evidence pack\" JSON). The run carries only signed fields; the receipt is ML-DSA-87 under the domain-separated autopilot context.",
        "properties": {
          "v": {
            "type": "integer"
          },
          "kind": {
            "type": "string",
            "const": "throndar-autopilot-run"
          },
          "created": {
            "type": "integer"
          },
          "run": {
            "type": "object",
            "description": "The sanitized run: goal, per-step outputs + verification flags, summary, budget accounting. No account data.",
            "properties": {
              "id": {
                "type": "string"
              },
              "goal": {
                "type": "string"
              },
              "status": {
                "type": "string"
              },
              "budgetCredits": {
                "type": "integer"
              },
              "spentCredits": {
                "type": "integer"
              },
              "maxSteps": {
                "type": "integer"
              },
              "summary": {
                "type": "string"
              },
              "stopReason": {
                "type": "string"
              },
              "steps": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            },
            "required": [
              "id",
              "goal",
              "steps"
            ]
          },
          "receipt": {
            "$ref": "#/components/schemas/ReceiptEnvelope"
          },
          "receiptKey": {
            "$ref": "#/components/schemas/ReceiptKey"
          }
        },
        "required": [
          "kind",
          "run"
        ]
      },
      "ExportArchive": {
        "type": "object",
        "description": "A SIGNED conversation export (the \"Download signed export\" JSON from GET /api/conversations/export?signed=1). The nested proof (proof.kind = 'throndar-export') carries an ML-DSA-87 receipt over a manifest that binds a SHA-256 of the whole conversations payload, under the domain-separated export context. Verification proves the archive is an unaltered, Throndar-signed export of exactly these conversations — not that the content is correct.",
        "properties": {
          "service": {
            "type": "string"
          },
          "exported": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "conversations": {
            "type": "array",
            "description": "The signed payload — the exact conversations the manifest's payload_sha256 commits to.",
            "items": {
              "type": "object"
            }
          },
          "signed_manifest": {
            "type": "string"
          },
          "proof": {
            "type": "object",
            "properties": {
              "v": {
                "type": "integer"
              },
              "kind": {
                "type": "string",
                "const": "throndar-export"
              },
              "context": {
                "type": "string",
                "description": "Carried for display only; the verifier PINS the export context and never trusts this."
              },
              "created": {
                "type": "integer"
              },
              "manifest": {
                "type": "string",
                "description": "JSON string binding payload_sha256 + conversation/message counts; this exact string is what the receipt signs."
              },
              "receipt": {
                "$ref": "#/components/schemas/ReceiptEnvelope"
              },
              "receiptKey": {
                "$ref": "#/components/schemas/ReceiptKey"
              }
            },
            "required": [
              "kind",
              "manifest",
              "receipt",
              "receiptKey"
            ]
          }
        },
        "required": [
          "conversations",
          "proof"
        ]
      },
      "SthBundle": {
        "type": "object",
        "description": "A Signed Tree Head — a transparency-log checkpoint from GET /api/transparency/ledger's `signed_tree_head` (accepted bare, or as the full ledger response with a nested `signed_tree_head`). The ML-DSA-87 receipt signs the tree-head string under the domain-separated STH context. Verification proves it is a genuine, unaltered Throndar commitment to (tree_size, root) at a time — append-only-ness itself needs a consistency proof between two checkpoints.",
        "properties": {
          "signed": {
            "type": "string",
            "description": "JSON string { log, tree_size, root_hash, timestamp } — the exact bytes the receipt signs."
          },
          "receipt": {
            "$ref": "#/components/schemas/ReceiptEnvelope"
          },
          "key": {
            "$ref": "#/components/schemas/ReceiptKey"
          }
        },
        "required": [
          "signed",
          "receipt",
          "key"
        ]
      },
      "ConsistencyBundle": {
        "type": "object",
        "description": "A consistency bundle from GET /api/transparency/ledger/consistency?signed=1 — two Throndar-signed tree heads plus the RFC 6962-bis consistency proof between them. Verification proves BOTH checkpoints are genuine AND the older signed root is an exact prefix of the newer (the log only appended between them — no rewrite or split-view), entirely offline.",
        "properties": {
          "kind": {
            "type": "string",
            "const": "throndar-consistency"
          },
          "old": {
            "$ref": "#/components/schemas/SthBundle"
          },
          "new": {
            "$ref": "#/components/schemas/SthBundle"
          },
          "proof": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "RFC 6962-bis consistency proof — hex Merkle node hashes relating the two signed roots."
          }
        },
        "required": [
          "kind",
          "old",
          "new",
          "proof"
        ]
      }
    }
  }
}
