{
  "openapi": "3.1.0",
  "info": {
    "title": "Sojourncase API",
    "version": "1.0.0",
    "description": "HTTP contract for the Sojourncase Rust/Axum API (apps/api). Bearer-JWT auth; most data is case-scoped under /api/cases/{caseId}/.... Operation ids are stable and match docs/agents/api-reference.md anchors and the agentic envelope meta.docs.endpoints map."
  },
  "servers": [
    { "url": "https://sojourn.cross-fare.com", "description": "Production (nginx: SPA static, /api/* proxied to the API)" }
  ],
  "tags": [
    { "name": "Auth", "description": "Registration, login, identity, logout (argon2id + HS256 JWT)." },
    { "name": "Visa", "description": "Seeded visa-type catalog and its requirements." },
    { "name": "Cases", "description": "Case CRUD, claim toggles, history feed, undo." },
    { "name": "Columns", "description": "Build-board workstream columns." },
    { "name": "Tasks", "description": "Tasks (incl. spawn-from-record)." },
    { "name": "Groups", "description": "Evidence groups." },
    { "name": "Docs", "description": "Evidence docs and real file attachments." },
    { "name": "Trackers", "description": "Specialized trackers, fields, configuration." },
    { "name": "Records", "description": "Tracker records, values, AI autofill." },
    { "name": "Draft", "description": "Petition draft: generate, review, sign-off (AI)." },
    { "name": "Credits", "description": "Credit balance and usage ledger." },
    { "name": "AgentLogin", "description": "Device-grant agent login: transient grants, claim, and connected-agent token management." },
    { "name": "Health", "description": "Liveness and readiness probes." }
  ],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/health": {
      "get": {
        "operationId": "health",
        "tags": ["Health"],
        "summary": "Liveness probe",
        "security": [],
        "responses": { "200": { "description": "ok", "content": { "text/plain": { "schema": { "type": "string", "example": "ok" } } } } }
      }
    },
    "/health/db": {
      "get": {
        "operationId": "healthDb",
        "tags": ["Health"],
        "summary": "Readiness probe (SELECT 1)",
        "security": [],
        "responses": {
          "200": { "description": "DB reachable" },
          "503": { "description": "DB unreachable" }
        }
      }
    },
    "/api/auth/register": {
      "post": {
        "operationId": "register",
        "tags": ["Auth"],
        "summary": "Register a new account",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegisterReq" } } } },
        "responses": {
          "201": { "description": "Account active; token issued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthResp" } } } },
          "202": { "description": "Account pending operator approval; no token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PendingResp" } } } },
          "403": { "$ref": "#/components/responses/AccessGated" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/auth/login": {
      "post": {
        "operationId": "login",
        "tags": ["Auth"],
        "summary": "Exchange credentials for a token",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginReq" } } } },
        "responses": {
          "200": { "description": "Authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthResp" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/AccessGated" }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "operationId": "getMe",
        "tags": ["Auth"],
        "summary": "Current user",
        "responses": {
          "200": { "description": "The authenticated user", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "operationId": "logout",
        "tags": ["Auth"],
        "summary": "Logout (stateless no-op)",
        "responses": {
          "204": { "description": "No content" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/visa-types": {
      "get": {
        "operationId": "listVisaTypes",
        "tags": ["Visa"],
        "summary": "List visa definitions",
        "responses": {
          "200": { "description": "All visa definitions", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/VisaDef" } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/visa-types/{visaId}": {
      "parameters": [{ "$ref": "#/components/parameters/VisaId" }],
      "get": {
        "operationId": "getVisaType",
        "tags": ["Visa"],
        "summary": "Get one visa definition",
        "responses": {
          "200": { "description": "The visa definition", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VisaDef" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases": {
      "get": {
        "operationId": "listCases",
        "tags": ["Cases"],
        "summary": "List the caller's cases",
        "responses": {
          "200": { "description": "Cases the user is a member of", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Case" } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "operationId": "createCase",
        "tags": ["Cases"],
        "summary": "Create a case",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCaseReq" } } } },
        "responses": {
          "201": { "description": "The seeded case", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Case" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/cases/{caseId}": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "get": {
        "operationId": "getCase",
        "tags": ["Cases"],
        "summary": "Get one case",
        "responses": {
          "200": { "description": "The fully-assembled case", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Case" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "patch": {
        "operationId": "patchCase",
        "tags": ["Cases"],
        "summary": "Update scalar case fields",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CasePatch" } } } },
        "responses": {
          "200": { "description": "The updated case", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Case" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      },
      "delete": {
        "operationId": "deleteCase",
        "tags": ["Cases"],
        "summary": "Delete a case (owner only)",
        "responses": {
          "204": { "description": "Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/claims/{req}": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "name": "req", "in": "path", "required": true, "description": "URL-encoded requirement name (keys claims).", "schema": { "type": "string" } }
      ],
      "put": {
        "operationId": "toggleClaim",
        "tags": ["Cases"],
        "summary": "Toggle a requirement claim",
        "responses": {
          "200": { "description": "The new claim state", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClaimResp" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/events": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "get": {
        "operationId": "listEvents",
        "tags": ["Cases"],
        "summary": "Case history feed",
        "parameters": [
          { "$ref": "#/components/parameters/Before" },
          { "name": "limit", "in": "query", "required": false, "description": "Rows per page (default 100, clamp 1-500).", "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 100 } }
        ],
        "responses": {
          "200": { "description": "Events, newest first", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CaseEvent" } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/cases/{caseId}/events/{eventId}/undo": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "name": "eventId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
      ],
      "post": {
        "operationId": "undoEvent",
        "tags": ["Cases"],
        "summary": "Undo an event (M3 stub: always 409)",
        "responses": {
          "409": { "$ref": "#/components/responses/Conflict" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/cases/{caseId}/columns": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "addColumn",
        "tags": ["Columns"],
        "summary": "Add a workstream column",
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddColumnReq" } } } },
        "responses": {
          "201": { "description": "New column id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IdResp" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/cases/{caseId}/columns/{colId}": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "name": "colId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
      ],
      "patch": {
        "operationId": "updateColumn",
        "tags": ["Columns"],
        "summary": "Rename and/or recolor a column",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ColumnPatch" } } } },
        "responses": {
          "200": { "description": "The updated column", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Column" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteColumn",
        "tags": ["Columns"],
        "summary": "Delete a column (reassign orphaned tasks)",
        "responses": {
          "200": { "description": "Post-delete columns + tasks snapshot", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteColumnResp" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/columns/{colId}/move": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "name": "colId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
      ],
      "post": {
        "operationId": "moveColumn",
        "tags": ["Columns"],
        "summary": "Reorder a column by one step",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MoveColumnReq" } } } },
        "responses": {
          "200": { "description": "The reordered column list", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Column" } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/cases/{caseId}/tasks": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "addTask",
        "tags": ["Tasks"],
        "summary": "Create a task",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } },
        "responses": {
          "201": { "description": "The created task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/cases/{caseId}/tasks/{taskId}": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "name": "taskId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
      ],
      "put": {
        "operationId": "updateTask",
        "tags": ["Tasks"],
        "summary": "Replace a task's mutable fields",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } },
        "responses": {
          "200": { "description": "The updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      },
      "delete": {
        "operationId": "deleteTask",
        "tags": ["Tasks"],
        "summary": "Delete a task",
        "responses": {
          "204": { "description": "Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/trackers/{trackerId}/records/{recordId}/spawn-task": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/TrackerId" },
        { "$ref": "#/components/parameters/RecordId" }
      ],
      "post": {
        "operationId": "spawnTask",
        "tags": ["Tasks"],
        "summary": "Spawn a follow-up task from a record",
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SpawnTaskReq" } } } },
        "responses": {
          "201": { "description": "New task id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IdResp" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/groups": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "addGroup",
        "tags": ["Groups"],
        "summary": "Add an evidence group",
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddGroupReq" } } } },
        "responses": {
          "201": { "description": "The created group", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Group" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/cases/{caseId}/docs": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "addDoc",
        "tags": ["Docs"],
        "summary": "Add an evidence doc",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddDocReq" } } } },
        "responses": {
          "201": { "description": "The created doc", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Doc" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/cases/{caseId}/docs/linked": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "addLinkedDoc",
        "tags": ["Docs"],
        "summary": "Add a doc linked to a Build effort",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddLinkedDocReq" } } } },
        "responses": {
          "201": { "description": "New doc id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IdResp" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/cases/{caseId}/docs/{docId}": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/DocId" }
      ],
      "delete": {
        "operationId": "deleteDoc",
        "tags": ["Docs"],
        "summary": "Delete a doc",
        "responses": {
          "204": { "description": "Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/docs/{docId}/status": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/DocId" }
      ],
      "patch": {
        "operationId": "setDocStatus",
        "tags": ["Docs"],
        "summary": "Set a doc's status",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetDocStatusReq" } } } },
        "responses": {
          "200": { "description": "The updated doc", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Doc" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/cases/{caseId}/docs/{docId}/source": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/DocId" }
      ],
      "put": {
        "operationId": "setDocSource",
        "tags": ["Docs"],
        "summary": "Link a doc to a source (or clear)",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LinkDocReq" } } } },
        "responses": {
          "200": { "description": "The updated doc", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Doc" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/cases/{caseId}/docs/{docId}/file": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/DocId" }
      ],
      "post": {
        "operationId": "uploadDocFile",
        "tags": ["Docs"],
        "summary": "Upload a file attachment (<=25MB, raw body)",
        "parameters": [
          { "name": "x-filename", "in": "header", "required": false, "description": "URI-encoded display filename.", "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } }
        },
        "responses": {
          "201": { "description": "The stored file metadata", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DocFile" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "413": { "$ref": "#/components/responses/PayloadTooLarge" }
        }
      },
      "get": {
        "operationId": "downloadDocFile",
        "tags": ["Docs"],
        "summary": "Download the file attachment (forced attachment)",
        "responses": {
          "200": {
            "description": "The decrypted bytes",
            "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteDocFile",
        "tags": ["Docs"],
        "summary": "Delete the file attachment",
        "responses": {
          "204": { "description": "Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/trackers": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "addTracker",
        "tags": ["Trackers"],
        "summary": "Create an unconfigured tracker",
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddTrackerReq" } } } },
        "responses": {
          "201": { "description": "New tracker id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IdResp" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/cases/{caseId}/trackers/{trackerId}": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/TrackerId" }
      ],
      "patch": {
        "operationId": "updateTracker",
        "tags": ["Trackers"],
        "summary": "Rename and/or recolor a tracker",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateTrackerReq" } } } },
        "responses": {
          "200": { "description": "The updated tracker", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Tracker" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteTracker",
        "tags": ["Trackers"],
        "summary": "Delete a tracker (fields/records cascade)",
        "responses": {
          "204": { "description": "Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/trackers/{trackerId}/fields": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/TrackerId" }
      ],
      "post": {
        "operationId": "addTrackerField",
        "tags": ["Trackers"],
        "summary": "Append a field to a tracker",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddFieldReq" } } } },
        "responses": {
          "201": { "description": "The created field", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrackerField" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/cases/{caseId}/trackers/{trackerId}/configure": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/TrackerId" }
      ],
      "put": {
        "operationId": "configureTracker",
        "tags": ["Trackers"],
        "summary": "Apply a stereotype (name+statuses+preset+fields)",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigureTrackerReq" } } } },
        "responses": {
          "200": { "description": "The configured tracker", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Tracker" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/api/cases/{caseId}/trackers/{trackerId}/records": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/TrackerId" }
      ],
      "post": {
        "operationId": "addRecord",
        "tags": ["Records"],
        "summary": "Create an empty record",
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddRecordReq" } } } },
        "responses": {
          "201": { "description": "The created record", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrackerRecord" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/trackers/{trackerId}/records/{recordId}": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/TrackerId" },
        { "$ref": "#/components/parameters/RecordId" }
      ],
      "patch": {
        "operationId": "updateRecord",
        "tags": ["Records"],
        "summary": "Partial-patch a record",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RecordPatch" } } } },
        "responses": {
          "200": { "description": "The updated record", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrackerRecord" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteRecord",
        "tags": ["Records"],
        "summary": "Delete a record",
        "responses": {
          "204": { "description": "Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/trackers/{trackerId}/records/{recordId}/values/{fieldId}": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/TrackerId" },
        { "$ref": "#/components/parameters/RecordId" },
        { "name": "fieldId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
      ],
      "put": {
        "operationId": "setRecordValue",
        "tags": ["Records"],
        "summary": "Set a single values[fieldId] key",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetRecordValueReq" } } } },
        "responses": {
          "200": { "description": "The updated record", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrackerRecord" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/trackers/{trackerId}/records/{recordId}/autofill": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "$ref": "#/components/parameters/TrackerId" },
        { "$ref": "#/components/parameters/RecordId" }
      ],
      "post": {
        "operationId": "autofillRecord",
        "tags": ["Records"],
        "summary": "AI autofill a record (2 credits; server-authoritative)",
        "description": "Runs a real provider lookup. No mock fallback: 503 before any charge if no provider / call fails. Charges 2 credits only when it delivers a fill/amend (cost>0). Returns the authoritative new balance and kinded suggestions.",
        "responses": {
          "200": { "description": "Suggestions + new balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AutofillResp" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "503": { "$ref": "#/components/responses/AiUnavailable" }
        }
      }
    },
    "/api/cases/{caseId}/draft": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "get": {
        "operationId": "getDraft",
        "tags": ["Draft"],
        "summary": "Get the persisted draft (204 if none)",
        "responses": {
          "200": { "description": "The draft", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Draft" } } } },
          "204": { "description": "No draft yet" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/cases/{caseId}/draft/generate": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "generateBrief",
        "tags": ["Draft"],
        "summary": "Generate the petition brief (48 credits; server-authoritative)",
        "description": "Builds the brief sections, resets review/signedOff, persists, charges 48. 503 before any charge if no provider / call fails.",
        "responses": {
          "200": { "description": "The new draft + balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DraftResp" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "503": { "$ref": "#/components/responses/AiUnavailable" }
        }
      }
    },
    "/api/cases/{caseId}/draft/review": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "reviewBrief",
        "tags": ["Draft"],
        "summary": "Run the adversarial review (24 credits; server-authoritative)",
        "description": "Requires an existing draft (400 otherwise). Sets draft.review, persists, charges 24. 503 before any charge if no provider / call fails.",
        "responses": {
          "200": { "description": "The reviewed draft + balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DraftResp" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "503": { "$ref": "#/components/responses/AiUnavailable" }
        }
      }
    },
    "/api/cases/{caseId}/draft/findings/{findingId}/task": {
      "parameters": [
        { "$ref": "#/components/parameters/CaseId" },
        { "name": "findingId", "in": "path", "required": true, "schema": { "type": "string" } }
      ],
      "post": {
        "operationId": "findingToTask",
        "tags": ["Draft"],
        "summary": "Create a task from a review finding",
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FindingTaskReq" } } } },
        "responses": {
          "201": { "description": "The created task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/cases/{caseId}/draft/signoff": {
      "parameters": [{ "$ref": "#/components/parameters/CaseId" }],
      "post": {
        "operationId": "signoffBrief",
        "tags": ["Draft"],
        "summary": "Sign off the draft to counsel",
        "responses": {
          "200": { "description": "The signed-off draft", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Draft" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/credits/balance": {
      "get": {
        "operationId": "getCredits",
        "tags": ["Credits"],
        "summary": "Current credit balance",
        "responses": {
          "200": { "description": "The balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreditBalance" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/credits/ledger": {
      "get": {
        "operationId": "getLedger",
        "tags": ["Credits"],
        "summary": "Credit usage ledger",
        "parameters": [
          { "$ref": "#/components/parameters/Before" },
          { "name": "limit", "in": "query", "required": false, "description": "Rows per page (default 50, clamp 1-200).", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }
        ],
        "responses": {
          "200": { "description": "Ledger entries, newest first", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/LedgerEntry" } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/agentic/login/transient": {
      "post": {
        "operationId": "agentLoginBootstrap",
        "tags": ["AgentLogin"],
        "summary": "Start a device-grant: mint a 5-minute transient grant (public)",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": {
          "type": "object", "required": ["name", "entityId"], "properties": {
            "name": { "type": "string", "maxLength": 64, "description": "Friendly agent name shown at consent." },
            "entityId": { "type": "string", "maxLength": 128, "description": "Stable agent identity; re-auth with the same value voids the prior token for this user." },
            "scope": { "type": "string", "enum": ["read", "write"], "default": "write" } } } } } },
        "responses": {
          "201": { "description": "Grant created", "content": { "application/json": { "schema": {
            "type": "object", "properties": {
              "transientToken": { "type": "string", "description": "Public grant id (the URL xxxx)." },
              "claimSecret": { "type": "string", "description": "PRIVATE — present on /claim; never in a URL." },
              "loginUrl": { "type": "string" }, "claimUrl": { "type": "string" }, "ackUrl": { "type": "string", "description": "POST here WITH the token to make it permanent (mandatory)." },
              "scopeRequested": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" },
              "pollIntervalSeconds": { "type": "integer" }, "docs": { "type": "string" } } } } } },
          "422": { "$ref": "#/components/responses/ValidationError" } } } },
    "/api/agentic/login/transient/{id}": {
      "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ],
      "get": {
        "operationId": "agentLoginStatus",
        "tags": ["AgentLogin"],
        "summary": "Status of a transient grant (drives the consent screen; user Bearer)",
        "responses": {
          "200": { "description": "Grant status", "content": { "application/json": { "schema": {
            "type": "object", "properties": {
              "agentName": { "type": "string" }, "scopeRequested": { "type": "string" },
              "scopeGranted": { "type": ["string", "null"] },
              "status": { "type": "string", "enum": ["pending", "approved", "delivered", "denied", "claimed", "expired"] },
              "expiresAt": { "type": "string", "format": "date-time" } } } } } },
          "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/api/agentic/login/transient/{id}/claim": {
      "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ],
      "post": {
        "operationId": "agentLoginClaim",
        "tags": ["AgentLogin"],
        "summary": "Poll for the permanent token using the private claim secret (public)",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": {
          "type": "object", "required": ["claimSecret"], "properties": { "claimSecret": { "type": "string" } } } } } },
        "responses": {
          "200": { "description": "Approved — a PROVISIONAL token returned ONCE; ack it to make it permanent", "content": { "application/json": { "schema": {
            "type": "object", "properties": {
              "status": { "type": "string" }, "token": { "type": "string", "description": "sjc_agent_… — shown once; provisional until acked." },
              "scope": { "type": "string" }, "name": { "type": "string" }, "ackUrl": { "type": "string" }, "message": { "type": "string" } } } } } },
          "202": { "description": "Still pending — keep polling" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "description": "Denied by the user" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "410": { "description": "Expired (past 5-min TTL) or already confirmed (acked)" } } } },
    "/api/agentic/login/transient/{id}/ack": {
      "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ],
      "post": {
        "operationId": "agentLoginAck",
        "tags": ["AgentLogin"],
        "summary": "Confirm receipt \u2014 signed WITH the token \u2014 to make it permanent (public)",
        "description": "Send Authorization: Bearer <the claimed token>. Promotes the provisional token to permanent, finalizes the grant, and voids the agent\u2019s prior token for the same (user, entityId).",
        "security": [],
        "responses": {
          "204": { "description": "Acked \u2014 token is now permanent" },
          "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/agentic/login/transient/{id}/approve": {
      "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ],
      "post": {
        "operationId": "agentLoginApprove",
        "tags": ["AgentLogin"],
        "summary": "Approve a grant (the signed-in user grants read|write)",
        "requestBody": { "required": false, "content": { "application/json": { "schema": {
          "type": "object", "properties": { "scope": { "type": "string", "enum": ["read", "write"] }, "alias": { "type": ["string", "null"], "maxLength": 64, "description": "Optional user label; the agent\u2019s name is kept regardless." } } } } } },
        "responses": {
          "200": { "description": "Approved" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "410": { "description": "Expired" } } } },
    "/api/agentic/login/transient/{id}/deny": {
      "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ],
      "post": {
        "operationId": "agentLoginDeny",
        "tags": ["AgentLogin"],
        "summary": "Deny a grant (the signed-in user refuses)",
        "responses": {
          "204": { "description": "Denied" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/api/auth/agent-tokens": {
      "get": {
        "operationId": "listAgentTokens",
        "tags": ["AgentLogin"],
        "summary": "List the caller's connected agents (live tokens)",
        "responses": {
          "200": { "description": "Connected agents", "content": { "application/json": { "schema": {
            "type": "array", "items": { "type": "object", "properties": {
              "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "alias": { "type": ["string", "null"] }, "entityId": { "type": ["string", "null"] }, "scope": { "type": "string" },
              "tokenPrefix": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" },
              "lastUsedAt": { "type": ["string", "null"], "format": "date-time" } } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/api/auth/agent-tokens/{tokenId}": {
      "parameters": [ { "name": "tokenId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ],
      "patch": {
        "operationId": "renameAgentToken",
        "tags": ["AgentLogin"],
        "summary": "Set/clear the caller\u2019s label (alias) for a token",
        "requestBody": { "required": false, "content": { "application/json": { "schema": {
          "type": "object", "properties": { "alias": { "type": ["string", "null"], "maxLength": 64 } } } } } },
        "responses": {
          "204": { "description": "Renamed" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" } } },
      "delete": {
        "operationId": "revokeAgentToken",
        "tags": ["AgentLogin"],
        "summary": "Revoke one of the caller's agent tokens",
        "responses": {
          "204": { "description": "Revoked" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/api/me/theme": {
      "put": {
        "operationId": "setTheme",
        "tags": ["Credits"],
        "summary": "Set theme (no-op echo)",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ThemeReq" } } } },
        "responses": {
          "200": { "description": "Echoed theme", "content": { "application/json": { "schema": { "type": "object", "properties": { "theme": { "type": "string", "enum": ["light", "dark"] } }, "required": ["theme"] } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "HS256 JWT from /api/auth/login (or open-mode /api/auth/register). sub = user uuid; TTL 7 days." }
    },
    "parameters": {
      "CaseId": { "name": "caseId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
      "TrackerId": { "name": "trackerId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
      "RecordId": { "name": "recordId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
      "DocId": { "name": "docId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
      "VisaId": { "name": "visaId", "in": "path", "required": true, "schema": { "type": "string", "examples": ["eb1a", "niw", "o1a", "eb1b"] } },
      "Before": { "name": "before", "in": "query", "required": false, "description": "RFC3339 cursor; only rows strictly older are returned.", "schema": { "type": "string", "format": "date-time" } }
    },
    "responses": {
      "Unauthorized": { "description": "Missing/invalid/expired token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Forbidden": { "description": "Not a case member, or insufficient role", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "Resource not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "BadRequest": { "description": "Malformed request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Conflict": { "description": "Conflict (duplicate email; non-reversible undo)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "ValidationError": { "description": "Validation failed (invalid enum value)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "PayloadTooLarge": { "description": "Upload exceeds 25 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "AccessGated": { "description": "Registration paused, or account pending/banned", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "AiUnavailable": { "description": "No AI provider configured, or the provider call/parse failed (no charge taken)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "string" } },
        "required": ["error"]
      },
      "RegisterReq": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "email": { "type": "string", "format": "email" },
          "password": { "type": "string" }
        },
        "required": ["name", "email", "password"]
      },
      "LoginReq": {
        "type": "object",
        "properties": {
          "email": { "type": "string", "format": "email" },
          "password": { "type": "string" }
        },
        "required": ["email", "password"]
      },
      "AuthResp": {
        "type": "object",
        "properties": {
          "token": { "type": "string" },
          "user": { "$ref": "#/components/schemas/User" }
        },
        "required": ["token", "user"]
      },
      "PendingResp": {
        "type": "object",
        "properties": {
          "pending": { "type": "boolean", "const": true },
          "message": { "type": "string" }
        },
        "required": ["pending", "message"]
      },
      "User": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "email": { "type": "string", "format": "email" }
        },
        "required": ["name", "email"]
      },
      "VisaRule": {
        "type": "object",
        "properties": {
          "kind": { "type": "string" },
          "n": { "type": "integer" }
        },
        "required": ["kind", "n"]
      },
      "VisaDef": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "full": { "type": "string" },
          "rule": { "$ref": "#/components/schemas/VisaRule" },
          "finalMerits": { "type": "boolean" },
          "offer": { "type": "boolean", "description": "Present only when true (EB-1B)." },
          "reqs": { "type": "array", "items": { "type": "string" } }
        },
        "required": ["id", "name", "full", "rule", "finalMerits", "reqs"]
      },
      "CreateCaseReq": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid", "description": "Optional client-supplied id." },
          "visa": { "type": "string" }
        },
        "required": ["visa"]
      },
      "CasePatch": {
        "type": "object",
        "description": "All keys optional; only present keys are written.",
        "properties": {
          "name": { "type": "string" },
          "status": { "type": "string" },
          "stage": { "$ref": "#/components/schemas/Stage" },
          "target": { "type": "string" },
          "receipt": { "type": "string" },
          "field": { "type": "string" },
          "attorney": { "type": "string" }
        }
      },
      "Stage": { "type": "string", "enum": ["build", "file", "after"] },
      "Priority": { "type": ["string", "null"], "enum": ["critical", "high", "medium", "low", null] },
      "DocStatus": { "type": "string", "enum": ["need", "draft", "final"] },
      "DocType": { "type": "string", "enum": ["file", "link", "draft"] },
      "FieldType": { "type": "string", "enum": ["text", "date", "select", "link"] },
      "Band": { "type": "string", "enum": ["s", "g", "t"], "description": "Strength band: strong / gap / threat." },
      "FindingKind": { "type": "string", "enum": ["gap", "rfe", "boilerplate"] },
      "Column": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "color": { "type": "string" }
        },
        "required": ["id", "name", "color"]
      },
      "Step": {
        "type": "object",
        "properties": {
          "t": { "type": "string" },
          "done": { "type": "boolean" }
        },
        "required": ["t", "done"]
      },
      "Task": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "colId": { "type": "string", "description": "Empty string or invalid uuid => no column." },
          "priority": { "$ref": "#/components/schemas/Priority" },
          "req": { "type": ["string", "null"] },
          "date": { "type": ["string", "null"] },
          "deadline": { "type": "boolean" },
          "notes": { "type": "string" },
          "steps": { "type": "array", "items": { "$ref": "#/components/schemas/Step" } },
          "docIds": { "type": "array", "items": { "type": "string" } },
          "done": { "type": "boolean" },
          "unreviewed": { "type": "boolean", "description": "Omitted when false." },
          "linkedRecordId": { "type": "string", "description": "Omitted when absent." }
        },
        "required": ["id", "title", "colId", "priority", "req", "date", "deadline", "notes", "steps", "docIds", "done"]
      },
      "Group": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "kind": { "type": "string", "enum": ["req", "user"] },
          "req": { "type": "string" },
          "strength": { "$ref": "#/components/schemas/Band" }
        },
        "required": ["id", "name", "kind"]
      },
      "DocSource": {
        "type": "object",
        "properties": {
          "kind": { "type": "string", "enum": ["task", "record"] },
          "taskId": { "type": "string" },
          "trackerId": { "type": "string" },
          "recordId": { "type": "string" }
        },
        "required": ["kind"]
      },
      "DocFile": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "filename": { "type": "string" },
          "contentType": { "type": "string" },
          "sizeBytes": { "type": "integer", "format": "int64" }
        },
        "required": ["id", "filename", "contentType", "sizeBytes"]
      },
      "Doc": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "groupId": { "type": "string" },
          "status": { "$ref": "#/components/schemas/DocStatus" },
          "type": { "$ref": "#/components/schemas/DocType" },
          "date": { "type": "string" },
          "unreviewed": { "type": "boolean", "description": "Omitted when false." },
          "source": { "$ref": "#/components/schemas/DocSource" },
          "file": { "$ref": "#/components/schemas/DocFile" }
        },
        "required": ["id", "title", "groupId", "status", "type", "date"]
      },
      "Person": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "role": { "type": "string" },
          "you": { "type": "boolean", "description": "Omitted when absent." }
        },
        "required": ["name", "role"]
      },
      "CaseEvent": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "t": { "type": "string", "description": "Humane day label (e.g. 'Jun 21')." },
          "text": { "type": "string", "description": "May contain inline HTML (rendered raw in the History feed)." },
          "src": { "type": "string" },
          "usage": { "type": "integer", "format": "int64", "description": "Credits spent by this event; omitted when absent." },
          "unreviewed": { "type": "boolean", "description": "Omitted when false." }
        },
        "required": ["id", "t", "text", "src"]
      },
      "TrackerField": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "type": { "$ref": "#/components/schemas/FieldType" },
          "options": { "type": "array", "items": { "type": "string" } }
        },
        "required": ["id", "name", "type"]
      },
      "TrackerRecord": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "values": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Keyed by field id." },
          "status": { "type": "string" },
          "nextAction": { "type": "string" },
          "req": { "type": ["string", "null"] },
          "notes": { "type": "string", "description": "Omitted when absent." },
          "privateNotes": { "type": "string", "description": "Omitted when absent." }
        },
        "required": ["id", "values", "status", "nextAction", "req"]
      },
      "Tracker": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "color": { "type": "string" },
          "preset": { "type": "string", "description": "Omitted when absent." },
          "fields": { "type": "array", "items": { "$ref": "#/components/schemas/TrackerField" } },
          "statuses": { "type": "array", "items": { "type": "string" } },
          "records": { "type": "array", "items": { "$ref": "#/components/schemas/TrackerRecord" } }
        },
        "required": ["id", "name", "color", "fields", "statuses", "records"]
      },
      "BriefSource": {
        "type": "object",
        "properties": {
          "kind": { "type": "string", "enum": ["exhibit", "effort", "field"] },
          "label": { "type": "string" },
          "docId": { "type": "string" },
          "taskId": { "type": "string" },
          "trackerId": { "type": "string" },
          "recordId": { "type": "string" }
        },
        "required": ["kind", "label"]
      },
      "BriefSection": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "req": { "type": ["string", "null"] },
          "body": { "type": "string" },
          "sources": { "type": "array", "items": { "$ref": "#/components/schemas/BriefSource" } }
        },
        "required": ["id", "title", "req", "body", "sources"]
      },
      "Finding": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "kind": { "$ref": "#/components/schemas/FindingKind" },
          "req": { "type": ["string", "null"] },
          "title": { "type": "string" },
          "detail": { "type": "string" },
          "band": { "$ref": "#/components/schemas/Band" },
          "taskId": { "type": "string", "description": "Set once a task is spawned from this finding." }
        },
        "required": ["id", "kind", "req", "title", "detail", "band"]
      },
      "DraftReview": {
        "type": "object",
        "properties": {
          "ranAt": { "type": "string" },
          "findings": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } }
        },
        "required": ["ranAt", "findings"]
      },
      "Draft": {
        "type": "object",
        "properties": {
          "generatedAt": { "type": ["string", "null"] },
          "sections": { "type": "array", "items": { "$ref": "#/components/schemas/BriefSection" } },
          "review": { "oneOf": [{ "$ref": "#/components/schemas/DraftReview" }, { "type": "null" }] },
          "signedOff": { "type": "boolean" }
        },
        "required": ["generatedAt", "sections", "review", "signedOff"]
      },
      "Case": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "visa": { "type": "string" },
          "name": { "type": "string" },
          "status": { "type": "string" },
          "stage": { "$ref": "#/components/schemas/Stage" },
          "target": { "type": "string" },
          "receipt": { "type": "string" },
          "field": { "type": "string" },
          "attorney": { "type": "string" },
          "claims": { "type": "object", "additionalProperties": { "type": "boolean" }, "description": "Keyed by requirement name." },
          "cols": { "type": "array", "items": { "$ref": "#/components/schemas/Column" } },
          "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/Task" } },
          "groups": { "type": "array", "items": { "$ref": "#/components/schemas/Group" } },
          "docs": { "type": "array", "items": { "$ref": "#/components/schemas/Doc" } },
          "people": { "type": "array", "items": { "$ref": "#/components/schemas/Person" } },
          "events": { "type": "array", "items": { "$ref": "#/components/schemas/CaseEvent" } },
          "trackers": { "type": "array", "items": { "$ref": "#/components/schemas/Tracker" } },
          "draft": { "$ref": "#/components/schemas/Draft" }
        },
        "required": ["id", "visa", "name", "status", "stage", "target", "receipt", "field", "attorney", "claims", "cols", "tasks", "groups", "docs", "people", "events", "trackers"]
      },
      "ClaimResp": {
        "type": "object",
        "properties": {
          "req": { "type": "string" },
          "claimed": { "type": "boolean" }
        },
        "required": ["req", "claimed"]
      },
      "MoveColumnReq": {
        "type": "object",
        "properties": { "dir": { "type": "integer", "enum": [-1, 1] } },
        "required": ["dir"]
      },
      "AddColumnReq": {
        "type": "object",
        "properties": { "id": { "type": "string", "format": "uuid" } }
      },
      "ColumnPatch": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "color": { "type": "string" }
        }
      },
      "DeleteColumnResp": {
        "type": "object",
        "properties": {
          "cols": { "type": "array", "items": { "$ref": "#/components/schemas/Column" } },
          "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/Task" } }
        },
        "required": ["cols", "tasks"]
      },
      "SpawnTaskReq": {
        "type": "object",
        "properties": { "id": { "type": "string", "format": "uuid" } }
      },
      "AddGroupReq": {
        "type": "object",
        "properties": { "id": { "type": "string", "format": "uuid" } }
      },
      "AddDocReq": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "groupId": { "type": "string", "format": "uuid" }
        },
        "required": ["groupId"]
      },
      "AddLinkedDocReq": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "source": { "$ref": "#/components/schemas/DocSource" },
          "title": { "type": "string" }
        },
        "required": ["source", "title"]
      },
      "SetDocStatusReq": {
        "type": "object",
        "properties": { "status": { "$ref": "#/components/schemas/DocStatus" } },
        "required": ["status"]
      },
      "LinkDocReq": {
        "type": "object",
        "description": "source=null clears the link.",
        "properties": { "source": { "oneOf": [{ "$ref": "#/components/schemas/DocSource" }, { "type": "null" }] } }
      },
      "AddTrackerReq": {
        "type": "object",
        "properties": { "id": { "type": "string", "format": "uuid" } }
      },
      "UpdateTrackerReq": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "color": { "type": "string" }
        }
      },
      "AddFieldReq": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "type": { "$ref": "#/components/schemas/FieldType" }
        },
        "required": ["name", "type"]
      },
      "ConfigFieldInput": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "type": { "$ref": "#/components/schemas/FieldType" },
          "options": { "type": "array", "items": { "type": "string" } }
        },
        "required": ["name", "type"]
      },
      "ConfigureTrackerReq": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "statuses": { "type": "array", "items": { "type": "string" } },
          "preset": { "type": "string" },
          "fields": { "type": "array", "items": { "$ref": "#/components/schemas/ConfigFieldInput" } }
        },
        "required": ["name", "statuses", "preset", "fields"]
      },
      "AddRecordReq": {
        "type": "object",
        "properties": { "id": { "type": "string", "format": "uuid" } }
      },
      "RecordPatch": {
        "type": "object",
        "description": "All keys optional. req is present-but-nullable: pass null to clear, omit to leave unchanged.",
        "properties": {
          "values": { "type": "object", "additionalProperties": { "type": "string" } },
          "status": { "type": "string" },
          "nextAction": { "type": "string" },
          "req": { "type": ["string", "null"] },
          "notes": { "type": "string" },
          "privateNotes": { "type": "string" }
        }
      },
      "SetRecordValueReq": {
        "type": "object",
        "properties": {
          "fieldId": { "type": "string", "description": "Optional; if present must match the path :fieldId." },
          "value": { "type": "string" }
        },
        "required": ["value"]
      },
      "FindingTaskReq": {
        "type": "object",
        "properties": { "id": { "type": "string", "format": "uuid" } }
      },
      "ThemeReq": {
        "type": "object",
        "properties": { "theme": { "type": "string", "enum": ["light", "dark"] } },
        "required": ["theme"]
      },
      "IdResp": {
        "type": "object",
        "properties": { "id": { "type": "string" } },
        "required": ["id"]
      },
      "DraftResp": {
        "type": "object",
        "properties": {
          "draft": { "$ref": "#/components/schemas/Draft" },
          "balance": { "type": "integer", "format": "int64" }
        },
        "required": ["draft", "balance"]
      },
      "AutofillSuggestion": {
        "type": "object",
        "properties": {
          "fieldId": { "type": "string" },
          "name": { "type": "string" },
          "kind": { "type": "string", "enum": ["fill", "amend", "confirm"] },
          "value": { "type": "string" },
          "current": { "type": "string" }
        },
        "required": ["fieldId", "name", "kind", "value", "current"]
      },
      "AutofillResp": {
        "type": "object",
        "properties": {
          "found": { "type": "boolean" },
          "note": { "type": "string" },
          "cost": { "type": "integer", "format": "int64" },
          "suggestions": { "type": "array", "items": { "$ref": "#/components/schemas/AutofillSuggestion" } },
          "balance": { "type": "integer", "format": "int64" }
        },
        "required": ["found", "note", "cost", "suggestions", "balance"]
      },
      "CreditBalance": {
        "type": "object",
        "properties": { "balance": { "type": "integer", "format": "int64" } },
        "required": ["balance"]
      },
      "LedgerEntry": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "format": "int64" },
          "delta": { "type": "integer", "format": "int64" },
          "reason": { "type": "string" },
          "at": { "type": "string", "format": "date-time" }
        },
        "required": ["id", "delta", "reason", "at"]
      }
    }
  }
}
