{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Calvinist Parrot Conversational API",
    "version": "1.0.0",
    "description": "Versioned contracts for Calvinist Parrot chat and Counsel of Three QA. Browser identity is always resolved server-side from the Appwrite session or server-managed guest cookie; v1 clients must not send `userId`."
  },
  "servers": [
    {
      "url": "/",
      "description": "Current Calvinist Parrot origin"
    }
  ],
  "tags": [
    {
      "name": "Chat",
      "description": "LangGraph-backed conversations."
    },
    {
      "name": "QA",
      "description": "Counsel of Three question answering."
    },
    {
      "name": "Legacy",
      "description": "Compatibility routes retained temporarily while clients migrate to v1."
    }
  ],
  "paths": {
    "/api/v1/chats": {
      "post": {
        "tags": [
          "Chat"
        ],
        "operationId": "createChat",
        "summary": "Create a chat",
        "description": "Creates a chat and persists the initial message. When `initialAnswer` is supplied, the answer and optional classification fields are also persisted so a QA result can continue as a chat. A caller-supplied `requestId` is scoped to the current browser actor: retrying the same payload returns the original identifiers, while reusing it for a different payload returns 409.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateChatRequest"
              },
              "example": {
                "initialQuestion": "What does justification by faith mean?",
                "denomination": "reformed-baptist",
                "clientChatId": "cm5h7x9k20000v8b4r3m2n1q0",
                "requestId": "f6bb8ec0-6d64-4c30-9f15-3eeebc61ff48"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Chat created or an identical creation replayed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateChatResponse"
                },
                "example": {
                  "chatId": "cm5h7x9k20000v8b4r3m2n1q0",
                  "messageId": "8b90be0d-497f-48cb-8c67-85c2e28f2e83",
                  "requestId": "f6bb8ec0-6d64-4c30-9f15-3eeebc61ff48"
                }
              }
            }
          },
          "400": {
            "description": "The request did not match the contract.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "The current browser actor does not own this chat.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "The requested chat or request was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "The request ID conflicts with another chat creation, or the client chat ID is already in use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The request failed before a stream could begin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chats/{chatId}": {
      "get": {
        "tags": [
          "Chat"
        ],
        "operationId": "getChat",
        "summary": "Get a chat transcript",
        "description": "Returns public chat metadata and normalized messages without exposing the internal ownership identifier.",
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Opaque chat identifier.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 191
            },
            "example": "cm5h7x9k20000v8b4r3m2n1q0"
          }
        ],
        "responses": {
          "200": {
            "description": "Chat and ordered transcript.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetChatResponse"
                },
                "example": {
                  "chat": {
                    "id": "cm5h7x9k20000v8b4r3m2n1q0",
                    "conversationName": "Justification by Faith",
                    "createdAt": "2026-07-26T14:30:00.000Z",
                    "modifiedAt": "2026-07-26T14:30:08.000Z",
                    "category": "Theology",
                    "subcategory": "Soteriology",
                    "issueType": "Primary",
                    "denomination": "reformed-baptist",
                    "effectiveDenomination": "reformed-baptist"
                  },
                  "messages": [
                    {
                      "id": "8b90be0d-497f-48cb-8c67-85c2e28f2e83",
                      "chatId": "cm5h7x9k20000v8b4r3m2n1q0",
                      "requestId": "f6bb8ec0-6d64-4c30-9f15-3eeebc61ff48",
                      "sender": "user",
                      "content": "What does justification by faith mean?",
                      "timestamp": "2026-07-26T14:30:00.000Z"
                    },
                    {
                      "id": "cm5h7x9k20001v8b4w6d5c4b3",
                      "chatId": "cm5h7x9k20000v8b4r3m2n1q0",
                      "requestId": "f6bb8ec0-6d64-4c30-9f15-3eeebc61ff48",
                      "sender": "parrot",
                      "content": "Justification is God's gracious declaration that a sinner is righteous through faith in Jesus Christ.",
                      "timestamp": "2026-07-26T14:30:08.000Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request did not match the contract.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "The current browser actor does not own this chat.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "The requested chat or request was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The request failed before a stream could begin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chats/{chatId}/messages": {
      "post": {
        "tags": [
          "Chat"
        ],
        "operationId": "sendChatMessage",
        "summary": "Stream a chat response",
        "description": "Starts a LangGraph response. Reusing a request ID with a different message, or retrying a request that already completed, returns 409 before streaming begins.",
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Opaque chat identifier.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 191
            },
            "example": "cm5h7x9k20000v8b4r3m2n1q0"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendChatMessageRequest"
              },
              "example": {
                "message": "How does Romans 3 explain this?",
                "requestId": "fa2d8424-b097-491d-b67c-1457a4986ee4",
                "messageId": "b60fc8bf-7c35-4e91-af98-b97610923676",
                "isAutoTrigger": false,
                "retry": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The response stream started.",
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ChatStreamEvent"
                },
                "description": "Newline-delimited JSON. Each line is one complete JSON object matching ChatStreamEvent. Once streaming begins, runtime failures are reported in-band as `error` events because the HTTP status has already been sent.",
                "example": {
                  "type": "parrot",
                  "content": "Romans 3 teaches that sinners are justified by grace",
                  "requestId": "fa2d8424-b097-491d-b67c-1457a4986ee4"
                }
              }
            }
          },
          "400": {
            "description": "The request did not match the contract.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "The current browser actor does not own this chat.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "The requested chat or request was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "The request ID conflicts with an existing message or completed response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The request failed before a stream could begin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chats/{chatId}/requests/{requestId}/stop": {
      "post": {
        "tags": [
          "Chat"
        ],
        "operationId": "stopChatRequest",
        "summary": "Stop an active response",
        "description": "Persists a terminal stop for a request. Completion, failure, and stop are idempotent terminal states.",
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Opaque chat identifier.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 191
            },
            "example": "cm5h7x9k20000v8b4r3m2n1q0"
          },
          {
            "name": "requestId",
            "in": "path",
            "required": true,
            "description": "Idempotency identifier for the user request to stop.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 191
            },
            "example": "f6bb8ec0-6d64-4c30-9f15-3eeebc61ff48"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StopChatRequest"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current terminal state for the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StopChatResponse"
                },
                "example": {
                  "stopped": true,
                  "completed": false
                }
              }
            }
          },
          "400": {
            "description": "The request did not match the contract.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "The current browser actor does not own this chat.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "The requested chat or request was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The request failed before a stream could begin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/qa": {
      "post": {
        "tags": [
          "QA"
        ],
        "operationId": "askQa",
        "summary": "Stream a Counsel of Three answer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QaRequest"
              },
              "example": {
                "question": "What is the doctrine of the Trinity?",
                "denomination": "reformed-baptist"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The QA stream started.",
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/QaStreamEvent"
                },
                "description": "Newline-delimited JSON. Each line is one complete JSON object matching QaStreamEvent. Once streaming begins, runtime failures are reported in-band as `error` events because the HTTP status has already been sent.",
                "example": {
                  "type": "reviewed_answer",
                  "content": "The Bible teaches that the one true God eternally exists as Father, Son, and Holy Spirit."
                }
              }
            }
          },
          "400": {
            "description": "The request did not match the contract.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "The current browser actor does not own this chat.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "The requested chat or request was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The request failed before a stream could begin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/parrot-chat": {
      "post": {
        "tags": [
          "Legacy"
        ],
        "operationId": "legacyParrotChatPost",
        "summary": "Legacy combined chat operation",
        "deprecated": true,
        "description": "Deprecated compatibility shim. Migrate to the operation-specific v1 chat routes.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LegacyParrotChatRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Legacy create/stop JSON response or message NDJSON stream, depending on the request shape.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/CreateChatResponse"
                    },
                    {
                      "$ref": "#/components/schemas/StopChatResponse"
                    }
                  ]
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ChatStreamEvent"
                },
                "description": "Newline-delimited JSON. Each line is one complete JSON object matching ChatStreamEvent. Once streaming begins, runtime failures are reported in-band as `error` events because the HTTP status has already been sent."
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "400": {
            "description": "The request did not match the contract.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "403": {
            "description": "The current browser actor does not own this chat.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "404": {
            "description": "The requested chat or request was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "409": {
            "description": "Legacy request ID conflict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "500": {
            "description": "The request failed before a stream could begin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Legacy"
        ],
        "operationId": "legacyParrotChatGet",
        "summary": "Legacy chat history",
        "deprecated": true,
        "parameters": [
          {
            "name": "chatId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 191
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Legacy chat history response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyGetChatResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "400": {
            "description": "The request did not match the contract.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "403": {
            "description": "The current browser actor does not own this chat.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "404": {
            "description": "The requested chat or request was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "500": {
            "description": "The request failed before a stream could begin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          }
        }
      }
    },
    "/api/parrot-qa": {
      "post": {
        "tags": [
          "Legacy"
        ],
        "operationId": "legacyParrotQa",
        "summary": "Legacy Counsel of Three stream",
        "deprecated": true,
        "description": "Deprecated compatibility shim. Migrate to `POST /api/v1/qa`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LegacyQaRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Legacy NDJSON payload served with its historical text media type.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/QaStreamEvent"
                },
                "description": "Newline-delimited JSON. Each line is one complete JSON object matching QaStreamEvent. Once streaming begins, runtime failures are reported in-band as `error` events because the HTTP status has already been sent."
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "400": {
            "description": "The request did not match the contract.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "403": {
            "description": "The current browser actor does not own this chat.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "404": {
            "description": "The requested chat or request was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          },
          "500": {
            "description": "The request failed before a stream could begin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Deprecation": {
                "description": "RFC 9745 date indicating when this compatibility endpoint was deprecated.",
                "schema": {
                  "type": "string",
                  "example": "@1785024000"
                }
              },
              "Link": {
                "description": "Migration documentation identified by the deprecation link relation.",
                "schema": {
                  "type": "string",
                  "example": "</api/v1/docs>; rel=\"deprecation\"; type=\"text/html\""
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false,
        "description": "A request-level error returned before streaming begins."
      },
      "CreateChatRequest": {
        "type": "object",
        "properties": {
          "initialQuestion": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "The initial question or message from the user."
          },
          "initialAnswer": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100000,
            "description": "An existing answer used to continue a QA result as a chat."
          },
          "denomination": {
            "type": "string",
            "enum": [
              "reformed-baptist",
              "presbyterian",
              "wesleyan",
              "lutheran",
              "anglican",
              "pentecostal",
              "non-denom"
            ],
            "description": "The theological tradition used to frame secondary doctrines."
          },
          "clientChatId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An opaque resource identifier."
          },
          "requestId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An idempotency identifier for one user request and its response."
          },
          "category": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "subcategory": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "issueType": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "required": [
          "initialQuestion"
        ],
        "additionalProperties": false,
        "description": "Creates a chat and persists its initial user message. A caller-supplied requestId makes identical retries return the original identifiers."
      },
      "CreateChatResponse": {
        "type": "object",
        "properties": {
          "chatId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An opaque resource identifier."
          },
          "messageId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An opaque resource identifier."
          },
          "requestId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An idempotency identifier for one user request and its response."
          }
        },
        "required": [
          "chatId",
          "messageId",
          "requestId"
        ],
        "additionalProperties": false,
        "description": "Identifiers needed to navigate to and continue the new chat."
      },
      "Chat": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An opaque resource identifier."
          },
          "conversationName": {
            "type": "string",
            "minLength": 1
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
            "description": "An RFC 3339 timestamp."
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
            "description": "An RFC 3339 timestamp."
          },
          "category": {
            "type": "string"
          },
          "subcategory": {
            "type": "string"
          },
          "issueType": {
            "type": "string"
          },
          "denomination": {
            "type": "string",
            "enum": [
              "reformed-baptist",
              "presbyterian",
              "wesleyan",
              "lutheran",
              "anglican",
              "pentecostal",
              "non-denom"
            ],
            "description": "The theological tradition used to frame secondary doctrines."
          },
          "effectiveDenomination": {
            "type": "string",
            "enum": [
              "reformed-baptist",
              "presbyterian",
              "wesleyan",
              "lutheran",
              "anglican",
              "pentecostal",
              "non-denom"
            ],
            "description": "The theological tradition used to frame secondary doctrines."
          }
        },
        "required": [
          "id",
          "conversationName",
          "createdAt",
          "modifiedAt",
          "category",
          "subcategory",
          "issueType",
          "denomination",
          "effectiveDenomination"
        ],
        "additionalProperties": false,
        "description": "Public chat metadata. Internal ownership identifiers are omitted."
      },
      "ChatMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An opaque resource identifier."
          },
          "chatId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An opaque resource identifier."
          },
          "requestId": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              },
              {
                "type": "null"
              }
            ]
          },
          "sender": {
            "type": "string",
            "enum": [
              "user",
              "parrot",
              "tool_summary",
              "system_error",
              "system_stopped"
            ]
          },
          "content": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
            "description": "An RFC 3339 timestamp."
          },
          "toolName": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "id",
          "chatId",
          "requestId",
          "sender",
          "content",
          "timestamp"
        ],
        "additionalProperties": false,
        "description": "One persisted message in a chat transcript."
      },
      "GetChatResponse": {
        "type": "object",
        "properties": {
          "chat": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An opaque resource identifier."
              },
              "conversationName": {
                "type": "string",
                "minLength": 1
              },
              "createdAt": {
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                "description": "An RFC 3339 timestamp."
              },
              "modifiedAt": {
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                "description": "An RFC 3339 timestamp."
              },
              "category": {
                "type": "string"
              },
              "subcategory": {
                "type": "string"
              },
              "issueType": {
                "type": "string"
              },
              "denomination": {
                "type": "string",
                "enum": [
                  "reformed-baptist",
                  "presbyterian",
                  "wesleyan",
                  "lutheran",
                  "anglican",
                  "pentecostal",
                  "non-denom"
                ],
                "description": "The theological tradition used to frame secondary doctrines."
              },
              "effectiveDenomination": {
                "type": "string",
                "enum": [
                  "reformed-baptist",
                  "presbyterian",
                  "wesleyan",
                  "lutheran",
                  "anglican",
                  "pentecostal",
                  "non-denom"
                ],
                "description": "The theological tradition used to frame secondary doctrines."
              }
            },
            "required": [
              "id",
              "conversationName",
              "createdAt",
              "modifiedAt",
              "category",
              "subcategory",
              "issueType",
              "denomination",
              "effectiveDenomination"
            ],
            "additionalProperties": false,
            "description": "Public chat metadata. Internal ownership identifiers are omitted."
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 191,
                  "description": "An opaque resource identifier."
                },
                "chatId": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 191,
                  "description": "An opaque resource identifier."
                },
                "requestId": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 191,
                      "description": "An idempotency identifier for one user request and its response."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "sender": {
                  "type": "string",
                  "enum": [
                    "user",
                    "parrot",
                    "tool_summary",
                    "system_error",
                    "system_stopped"
                  ]
                },
                "content": {
                  "type": "string"
                },
                "timestamp": {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                  "description": "An RFC 3339 timestamp."
                },
                "toolName": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "required": [
                "id",
                "chatId",
                "requestId",
                "sender",
                "content",
                "timestamp"
              ],
              "additionalProperties": false,
              "description": "One persisted message in a chat transcript."
            }
          }
        },
        "required": [
          "chat",
          "messages"
        ],
        "additionalProperties": false,
        "description": "A chat and its ordered, normalized transcript."
      },
      "SendChatMessageRequest": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "The initial question or message from the user."
          },
          "requestId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An idempotency identifier for one user request and its response."
          },
          "messageId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 191,
            "description": "An opaque resource identifier."
          },
          "isAutoTrigger": {
            "type": "boolean"
          },
          "retry": {
            "type": "boolean"
          }
        },
        "required": [
          "message"
        ],
        "additionalProperties": false,
        "description": "Starts or retries one streamed response in an existing chat."
      },
      "ChatStreamEvent": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "progress"
              },
              "title": {
                "type": "string"
              },
              "content": {
                "type": "string"
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              }
            },
            "required": [
              "type",
              "title",
              "content",
              "requestId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "tool_progress"
              },
              "toolName": {
                "type": "string",
                "minLength": 1
              },
              "message": {
                "type": "string"
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              }
            },
            "required": [
              "type",
              "toolName",
              "message",
              "requestId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "tool_summary"
              },
              "toolName": {
                "type": "string",
                "minLength": 1
              },
              "content": {
                "type": "string"
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              }
            },
            "required": [
              "type",
              "toolName",
              "content",
              "requestId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "parrot"
              },
              "content": {
                "type": "string"
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              }
            },
            "required": [
              "type",
              "content",
              "requestId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "conversationNameUpdated"
              },
              "chatId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An opaque resource identifier."
              },
              "name": {
                "type": "string",
                "minLength": 1
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              }
            },
            "required": [
              "type",
              "chatId",
              "name",
              "requestId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "error"
              },
              "stage": {
                "type": "string",
                "minLength": 1
              },
              "message": {
                "type": "string",
                "minLength": 1
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              }
            },
            "required": [
              "type",
              "stage",
              "message",
              "requestId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "done"
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              }
            },
            "required": [
              "type",
              "requestId"
            ],
            "additionalProperties": false
          }
        ],
        "description": "One NDJSON line emitted while the LangGraph-backed chat response runs."
      },
      "StopChatRequest": {
        "type": "object",
        "properties": {},
        "additionalProperties": false,
        "description": "The stop operation has no body fields; chatId and requestId are path parameters."
      },
      "StopChatResponse": {
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "stopped": {
                "type": "boolean",
                "const": true
              },
              "completed": {
                "type": "boolean",
                "const": false
              }
            },
            "required": [
              "stopped",
              "completed"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "stopped": {
                "type": "boolean",
                "const": false
              },
              "completed": {
                "type": "boolean",
                "const": true
              }
            },
            "required": [
              "stopped",
              "completed"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "stopped": {
                "type": "boolean",
                "const": false
              },
              "completed": {
                "type": "boolean",
                "const": false
              },
              "failed": {
                "type": "boolean",
                "const": true
              }
            },
            "required": [
              "stopped",
              "completed",
              "failed"
            ],
            "additionalProperties": false
          }
        ]
      },
      "QaRequest": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "A Bible or theology question for the Counsel of Three pipeline."
          },
          "denomination": {
            "type": "string",
            "enum": [
              "reformed-baptist",
              "presbyterian",
              "wesleyan",
              "lutheran",
              "anglican",
              "pentecostal",
              "non-denom"
            ],
            "description": "The theological tradition used to frame secondary doctrines."
          }
        },
        "required": [
          "question"
        ],
        "additionalProperties": false,
        "description": "Starts a streamed Counsel of Three response."
      },
      "QaStreamEvent": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "progress"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "type",
              "message"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "categorization"
              },
              "data": {
                "type": "object",
                "properties": {
                  "reformatted_question": {
                    "type": "string"
                  },
                  "category": {
                    "type": "string"
                  },
                  "subcategory": {
                    "type": "string"
                  },
                  "issue_type": {
                    "type": "string"
                  }
                },
                "required": [
                  "reformatted_question",
                  "category",
                  "subcategory",
                  "issue_type"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "type",
              "data"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "agent_responses"
              },
              "data": {
                "type": "object",
                "properties": {
                  "first_answer": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "second_answer": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "third_answer": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "first_answer",
                  "second_answer",
                  "third_answer"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "type",
              "data"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "calvin_review"
              },
              "content": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "type",
              "content"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "reviewed_answer"
              },
              "content": {
                "type": "string"
              }
            },
            "required": [
              "type",
              "content"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "refusal"
              },
              "content": {
                "type": "string"
              }
            },
            "required": [
              "type",
              "content"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "error"
              },
              "stage": {
                "type": "string",
                "minLength": 1
              },
              "message": {
                "type": "string",
                "minLength": 1
              }
            },
            "required": [
              "type",
              "stage",
              "message"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "done"
              }
            },
            "required": [
              "type"
            ],
            "additionalProperties": false
          }
        ],
        "description": "One NDJSON line emitted by the Counsel of Three pipeline."
      },
      "LegacyParrotChatRequest": {
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "chatId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An opaque resource identifier."
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              },
              "stop": {
                "type": "boolean",
                "const": true
              }
            },
            "required": [
              "chatId",
              "requestId",
              "stop"
            ],
            "additionalProperties": false,
            "description": "Deprecated legacy shape for stopping a response."
          },
          {
            "type": "object",
            "properties": {
              "chatId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An opaque resource identifier."
              },
              "message": {
                "type": "string",
                "minLength": 1,
                "maxLength": 20000,
                "description": "The initial question or message from the user."
              },
              "userId": {
                "description": "Deprecated and ignored; identity is resolved from cookies.",
                "type": "string"
              },
              "denomination": {
                "type": "string",
                "enum": [
                  "reformed-baptist",
                  "presbyterian",
                  "wesleyan",
                  "lutheran",
                  "anglican",
                  "pentecostal",
                  "non-denom"
                ],
                "description": "The theological tradition used to frame secondary doctrines."
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              },
              "messageId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An opaque resource identifier."
              },
              "isAutoTrigger": {
                "type": "boolean"
              },
              "retry": {
                "type": "boolean"
              }
            },
            "required": [
              "chatId",
              "message"
            ],
            "additionalProperties": false,
            "description": "Deprecated legacy shape for sending a chat message."
          },
          {
            "type": "object",
            "properties": {
              "initialQuestion": {
                "type": "string",
                "minLength": 1,
                "maxLength": 20000,
                "description": "The initial question or message from the user."
              },
              "initialAnswer": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100000,
                "description": "An existing answer used to continue a QA result as a chat."
              },
              "userId": {
                "description": "Deprecated and ignored; identity is resolved from cookies.",
                "type": "string"
              },
              "denomination": {
                "type": "string",
                "enum": [
                  "reformed-baptist",
                  "presbyterian",
                  "wesleyan",
                  "lutheran",
                  "anglican",
                  "pentecostal",
                  "non-denom"
                ],
                "description": "The theological tradition used to frame secondary doctrines."
              },
              "clientChatId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An opaque resource identifier."
              },
              "requestId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An idempotency identifier for one user request and its response."
              },
              "category": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "subcategory": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "issue_type": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "initialQuestion"
            ],
            "additionalProperties": false,
            "description": "Deprecated legacy shape for creating a chat."
          }
        ]
      },
      "LegacyGetChatResponse": {
        "type": "object",
        "properties": {
          "chat": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An opaque resource identifier."
              },
              "conversationName": {
                "type": "string",
                "minLength": 1
              },
              "createdAt": {
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                "description": "An RFC 3339 timestamp."
              },
              "modifiedAt": {
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                "description": "An RFC 3339 timestamp."
              },
              "category": {
                "type": "string"
              },
              "subcategory": {
                "type": "string"
              },
              "denomination": {
                "type": "string",
                "enum": [
                  "reformed-baptist",
                  "presbyterian",
                  "wesleyan",
                  "lutheran",
                  "anglican",
                  "pentecostal",
                  "non-denom"
                ],
                "description": "The theological tradition used to frame secondary doctrines."
              },
              "effectiveDenomination": {
                "type": "string",
                "enum": [
                  "reformed-baptist",
                  "presbyterian",
                  "wesleyan",
                  "lutheran",
                  "anglican",
                  "pentecostal",
                  "non-denom"
                ],
                "description": "The theological tradition used to frame secondary doctrines."
              },
              "issue_type": {
                "type": "string"
              },
              "userId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 191,
                "description": "An opaque resource identifier."
              }
            },
            "required": [
              "id",
              "conversationName",
              "createdAt",
              "modifiedAt",
              "category",
              "subcategory",
              "denomination",
              "effectiveDenomination",
              "issue_type",
              "userId"
            ],
            "additionalProperties": false
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 191,
                  "description": "An opaque resource identifier."
                },
                "chatId": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 191,
                  "description": "An opaque resource identifier."
                },
                "requestId": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 191,
                      "description": "An idempotency identifier for one user request and its response."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "sender": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "user",
                        "parrot",
                        "tool_summary",
                        "system_error",
                        "system_stopped"
                      ]
                    },
                    {
                      "type": "string",
                      "const": "calvin"
                    }
                  ]
                },
                "content": {
                  "type": "string"
                },
                "timestamp": {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                  "description": "An RFC 3339 timestamp."
                },
                "toolName": {
                  "type": "string",
                  "minLength": 1
                },
                "raw": {
                  "anyOf": [
                    {},
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "id",
                "chatId",
                "requestId",
                "sender",
                "content",
                "timestamp"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "chat",
          "messages"
        ],
        "additionalProperties": false,
        "description": "Deprecated legacy chat history shape."
      },
      "LegacyQaRequest": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "A Bible or theology question for the Counsel of Three pipeline."
          },
          "denomination": {
            "type": "string",
            "enum": [
              "reformed-baptist",
              "presbyterian",
              "wesleyan",
              "lutheran",
              "anglican",
              "pentecostal",
              "non-denom"
            ],
            "description": "The theological tradition used to frame secondary doctrines."
          },
          "userId": {
            "description": "Deprecated external identity accepted only by the legacy route.",
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "question"
        ],
        "additionalProperties": false,
        "description": "Deprecated request shape for the legacy QA route."
      }
    }
  }
}
