{
  "openapi": "3.1.0",
  "info": {
    "title": "COHESION Judgment Independence Score API",
    "version": "1.10.0",
    "summary": "Real-time measurement of human oversight of AI, the EU AI Act Article 14 compliance layer.",
    "x-deprecations": [
      {
        "id": "body-api-key",
        "introduced": "2026-04-17",
        "sunset": "2026-07-15",
        "replacement": "X-API-Key header",
        "headers_emitted": [
          "Deprecation: true",
          "Sunset: Wed, 15 Jul 2026 00:00:00 GMT"
        ],
        "description": "Passing `api_key` in the POST body is deprecated. Clients receive\n`Deprecation: true` + `Sunset` response headers when doing so. The\nfield is removed from the API on 2026-07-15; after that date\nbody-auth returns 401 with the uniform UNAUTHORIZED envelope.\n"
      }
    ],
    "description": "The COHESION Judgment Independence Score (JIS) API measures, in real time, whether\nhumans working alongside AI are genuinely exercising judgment or rubber-stamping\nAI output. It produces per-interaction scores across seven judgment dimensions,\nprojects judgment decay over time, and generates EU AI Act Article 14 compliance\nevidence.\n\nThis is the authoritative public contract. The source of truth is this document\nand the normative rulebook at\n[the COHESION certification spec v1.1](https://cohesionauth.com/standard).\n\n## How scoring works\n\nEvery call to `POST /v1/score` accepts a single human-AI interaction described by\nten behavioural fields (time-to-decision, decision class, modification extent,\nhover events, scroll depth, and more). The service computes the Judgment\nIndependence Score as a weighted sum of seven dimensions, projects the expected\ndecay curve for the operator's domain, and returns a machine-readable compliance\nstatus plus a recommended maintenance intervention, all without surfacing any\nof that feedback to the operator (the intervention is adaptive by design).\n\n## Authentication\n\nEvery authenticated request requires an API key scoped to a single organization,\npassed in the `X-API-Key` request header. Passing the key in the JSON request body\nas `api_key` is accepted but **deprecated as of 2026-04-17** (sunset 2026-07-15);\ndeprecated-surface callers receive `Deprecation: true`, `Sunset`, and `Link`\nresponse headers. Inactive organizations always receive `401`. Auth outcomes are\nuniform at the wire level with an 80 ms timing floor to prevent enumeration.\n\nTwo endpoints are intentionally public: `POST /assessments` and\n`GET /assessments/{sessionId}` (the public demo submission surface). They require\nno key and are limited only by Layer 1 per-IP rate limiting.\n\n## Rate limits\n\nEach API key is limited to **1000 requests per 60-second sliding window**. Over-limit\ncallers receive `429 Too Many Requests`.\n\n## Body size limits\n\n- Single scoring (`POST /v1/score`, `POST /v1/maintenance/recommend`): 1 MB\n- Batch scoring (`POST /v1/score/batch`): 5 MB\n\nBoth the `Content-Length` header and the actual received byte length are enforced.\nOver-cap bodies receive `413 Payload Too Large`.\n\n## CORS\n\nCross-origin calls are accepted only from origins that the organization has\nexplicitly registered on their account. Wildcard origins are never honoured.\nMis-registered or unknown origins receive `403` on `OPTIONS` preflight with no\n`Access-Control-Allow-Origin` reflection.\n\n## Patent notice\n\nU.S. provisional patents pending: App 64/038,246 (filed 2026-04-13) and\nApp 64/051,131 (filed 2026-04-28), both Customer 230082 — covering the\nhosted measurement service, behavioural telemetry, JIS computation, and\nadaptive-calibration loop. (c) 2026 COHESION AUTH LLC.\n",
    "contact": {
      "name": "COHESION AUTH LLC",
      "email": "peyton@cohesionauth.com",
      "url": "https://cohesionauth.com"
    },
    "license": {
      "name": "COHESION Commercial License",
      "url": "https://cohesionauth.com/terms.html"
    },
    "termsOfService": "https://cohesionauth.com/terms.html"
  },
  "servers": [
    {
      "url": "https://api.cohesionauth.com",
      "description": "Production (custom domain, live)"
    }
  ],
  "security": [
    {
      "apiKeyHeader": []
    },
    {
      "apiKeyBody": []
    }
  ],
  "tags": [
    {
      "name": "Service",
      "description": "Health check and self-describe metadata."
    },
    {
      "name": "Scoring",
      "description": "Score individual or batched human-AI interactions."
    },
    {
      "name": "Operator",
      "description": "Retrieve an operator's judgment profile over time."
    },
    {
      "name": "Organization",
      "description": "Aggregate dashboards across all operators in an organization."
    },
    {
      "name": "Maintenance",
      "description": "Recommend and track adaptive-calibration interventions."
    },
    {
      "name": "Compliance",
      "description": "Generate EU AI Act Article 14 compliance reports."
    },
    {
      "name": "Admin",
      "description": "Self-serve key lifecycle and audit log access. All admin endpoints require\n`X-API-Key` header auth, are Layer 2 rate-limited, and write every action\nto `audit_log` scoped to the authenticated org.\n"
    },
    {
      "name": "Demo",
      "description": "Public demo submission surface used by the `/demo/` interactive experience.\nUnauthenticated, IP-rate-limited (Layer 1). Not part of `/v1`.\n"
    }
  ],
  "paths": {
    "/": {
      "get": {
        "tags": [
          "Service"
        ],
        "summary": "Health check",
        "description": "Returns service liveness. No authentication required.",
        "operationId": "healthCheck",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is live.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "example": {
                  "status": "ok",
                  "service": "COHESION Judgment Independence Score API",
                  "version": "1.0.0",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "head": {
        "tags": [
          "Service"
        ],
        "summary": "Health check (HEAD)",
        "description": "Mirrors `GET /` for uptime monitors that default to HEAD (Pingdom,\nBetterUptime, UptimeRobot, Cloudflare healthchecks). Returns the\nsame status and `Content-Type` as `GET /` with an empty body per\nRFC 7231 §4.3.2.\n",
        "operationId": "healthCheckHead",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is live (empty body).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1": {
      "get": {
        "tags": [
          "Service"
        ],
        "summary": "API self-describe",
        "description": "Returns a machine-readable summary of this API version, its endpoints, the\nregulatory frameworks it satisfies, and the patent status.\n",
        "operationId": "apiInfo",
        "security": [],
        "responses": {
          "200": {
            "description": "API metadata.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIInfoResponse"
                },
                "example": {
                  "service": "COHESION Judgment Independence Score API",
                  "version": "1.0.0",
                  "endpoints": {
                    "POST /v1/score": "Score a single human-AI interaction",
                    "POST /v1/score/batch": "Score multiple interactions in one request",
                    "GET /v1/operator/:id/profile": "Get operator judgment profile over time",
                    "GET /v1/organization/dashboard": "Aggregate organization scores",
                    "POST /v1/maintenance/recommend": "Get maintenance intervention recommendation",
                    "GET /v1/compliance/report": "Generate EU AI Act Article 14 compliance report",
                    "POST /assessments": "Submit a public demo assessment (unauthenticated; rate-limited per IP)",
                    "GET /assessments/:sessionId": "Retrieve a shared demo assessment by session ID",
                    "POST /v1/admin/key/rotate": "Self-serve key rotation (returns new key ONCE)",
                    "POST /v1/admin/key/revoke": "Self-serve revocation (sets active = 0)",
                    "GET /v1/admin/audit-log": "Own-org audit log (filters: event_type, since, until, limit)"
                  },
                  "compliance": [
                    "EU AI Act Article 14",
                    "NIST AI RMF",
                    "ISO/IEC 42001"
                  ],
                  "patent": {
                    "status": "pending",
                    "filed": "2026-04-13",
                    "confirmation": "1414",
                    "claims": 31
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/score": {
      "post": {
        "tags": [
          "Scoring"
        ],
        "summary": "Score a single interaction",
        "description": "Scores a single human-AI interaction and persists it to the operator's\nrecord. Returns the Judgment Independence Score, all seven dimension\nscores, a projected decay curve, the Article-14 compliance status, and an\nadaptive-calibration recommendation.\n",
        "operationId": "scoreInteraction",
        "parameters": [
          {
            "in": "query",
            "name": "mode",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "full",
                "lite"
              ],
              "default": "full"
            },
            "description": "Scoring mode. `full` (default) returns all 7 judgment dimensions.\n`lite` computes only D1 (Deferral Resistance), D4 (Deliberation Depth),\nand D7 (Decision Autonomy) with renormalized weights summing to 1.00.\nUse lite when the caller cannot supply outcome labels, calibration\ncontext, or withheld-AI counterfactuals. Alternate: `X-Cohesion-Mode`\nheader. Query wins if both are present.\n"
          },
          {
            "in": "query",
            "name": "role_tier",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "tier_1",
                "tier_2",
                "tier_3"
              ],
              "default": "tier_1"
            },
            "description": "Operator skill tier. Section 1 plumbs this through the response envelope;\ntier-specific Adaptive Calibration deltas ship in Section 4. Senior\nanalysts close templated alerts in seconds by design and should not be\nread as rubber-stampers. Alternate: `X-Cohesion-Role-Tier` header.\nQuery wins if both are present.\n"
          },
          {
            "in": "query",
            "name": "mode_override",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "normal",
                "incident_frozen"
              ],
              "default": "normal"
            },
            "description": "Operational mode override. `normal` (default) computes JIS as usual.\n`incident_frozen` returns a skipped envelope with no JIS computation\nfor active-incident scenarios where the analyst is acting, not\ndeliberating, and hover/scroll behavior would mis-read as\nrubber-stamping. Alternate: `X-Cohesion-Mode-Override` header.\nQuery wins if both are present.\n"
          },
          {
            "in": "header",
            "name": "X-Cohesion-Mode",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "full",
                "lite"
              ]
            },
            "description": "Alternate to `?mode` query parameter. Query wins if both present.\n"
          },
          {
            "in": "header",
            "name": "X-Cohesion-Role-Tier",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "tier_1",
                "tier_2",
                "tier_3"
              ]
            },
            "description": "Alternate to `?role_tier` query parameter. Query wins if both present.\n"
          },
          {
            "in": "header",
            "name": "X-Cohesion-Mode-Override",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "normal",
                "incident_frozen"
              ]
            },
            "description": "Alternate to `?mode_override` query parameter. Query wins if both present.\n"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScoreRequest"
              },
              "example": {
                "api_key": "ak_live_00000000000000000000000000000000",
                "session_id": "sess_2026-04-16_0001",
                "operator_id": "op_12345",
                "domain": "healthcare",
                "interaction": {
                  "ai_recommendation_presented": true,
                  "time_to_decision_ms": 14200,
                  "decision": "modified",
                  "modification_extent": 0.35,
                  "ai_available": true,
                  "scenario_type": "standard",
                  "outcome_correct": true,
                  "hover_events": 6,
                  "scroll_depth": 0.82,
                  "alternative_views_checked": 2
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Interaction scored and persisted.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScoreResponse"
                },
                "example": {
                  "jis": 74.2,
                  "dimensions": {
                    "deferral_resistance": 71,
                    "error_detection_capability": 76.5,
                    "independent_performance": 72.4,
                    "deliberation_depth": 78.1,
                    "post_error_recalibration": 70.3,
                    "domain_confidence": 75,
                    "decision_autonomy": 73.8
                  },
                  "decay_projection": {
                    "domain": "healthcare",
                    "alpha": 0.12,
                    "beta": 0.08,
                    "floor": 35,
                    "current_trend": "stable",
                    "projected_jis_30d": 71.3,
                    "projected_jis_90d": 66.8,
                    "mitigated_projected_jis_90d": 73.5
                  },
                  "compliance": {
                    "article_14_status": "at_risk",
                    "band": "adequate",
                    "notes": "Operator above minimum threshold; targeted deferral-resistance maintenance recommended."
                  },
                  "maintenance_recommendation": {
                    "trigger_intervention": true,
                    "intervention_type": "single_dimension_boost",
                    "urgency": "low",
                    "rationale": "deferral_resistance < band_floor_75; schedule targeted calibration injection."
                  },
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidJSON"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedBodyAuth"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/score/batch": {
      "post": {
        "tags": [
          "Scoring"
        ],
        "summary": "Score up to 100 interactions",
        "description": "Scores a batch of up to 100 interactions for the same operator. All\ninteractions in the batch must be for the same domain. Useful for\nback-filling historical data or for offline batch pipelines.\n",
        "operationId": "scoreBatch",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScoreBatchRequest"
              },
              "example": {
                "operator_id": "op_12345",
                "domain": "healthcare",
                "interactions": [
                  {
                    "ai_recommendation_presented": true,
                    "time_to_decision_ms": 14200,
                    "decision": "modified",
                    "modification_extent": 0.35,
                    "ai_available": true,
                    "scenario_type": "standard",
                    "outcome_correct": true,
                    "hover_events": 6,
                    "scroll_depth": 0.82,
                    "alternative_views_checked": 2
                  },
                  {
                    "ai_recommendation_presented": true,
                    "time_to_decision_ms": 9800,
                    "decision": "accepted",
                    "modification_extent": 0,
                    "ai_available": true,
                    "scenario_type": "trap",
                    "outcome_correct": false,
                    "hover_events": 1,
                    "scroll_depth": 0.21,
                    "alternative_views_checked": 0
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "All interactions scored.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScoreBatchResponse"
                },
                "example": {
                  "results": [
                    {
                      "jis": 74.2,
                      "dimensions": {
                        "deferral_resistance": 71,
                        "error_detection_capability": 76.5,
                        "independent_performance": 72.4,
                        "deliberation_depth": 78.1,
                        "post_error_recalibration": 70.3,
                        "domain_confidence": 75,
                        "decision_autonomy": 73.8
                      },
                      "decay_projection": {
                        "domain": "healthcare",
                        "alpha": 0.12,
                        "beta": 0.08,
                        "floor": 35,
                        "current_trend": "stable",
                        "projected_jis_30d": 71.3,
                        "projected_jis_90d": 66.8,
                        "mitigated_projected_jis_90d": 73.5
                      }
                    },
                    {
                      "jis": 58.9,
                      "dimensions": {
                        "deferral_resistance": 54.2,
                        "error_detection_capability": 52,
                        "independent_performance": 60.1,
                        "deliberation_depth": 61.8,
                        "post_error_recalibration": 59,
                        "domain_confidence": 63.5,
                        "decision_autonomy": 61
                      },
                      "decay_projection": {
                        "domain": "healthcare",
                        "alpha": 0.12,
                        "beta": 0.08,
                        "floor": 35,
                        "current_trend": "declining",
                        "projected_jis_30d": 54.1,
                        "projected_jis_90d": 47.3,
                        "mitigated_projected_jis_90d": 60
                      }
                    }
                  ],
                  "count": 2,
                  "operator_id": "op_12345",
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidJSON"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedBodyAuth"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/operator/{operator_id}/profile": {
      "get": {
        "tags": [
          "Operator"
        ],
        "summary": "Get operator judgment profile",
        "description": "Returns the operator's complete judgment profile: current JIS, per-dimension\nscores, domain decay parameters, and the full JIS history as a sparkline.\n",
        "operationId": "getOperatorProfile",
        "parameters": [
          {
            "name": "operator_id",
            "in": "path",
            "required": true,
            "description": "The organization-scoped operator identifier. Alphanumeric, hyphens,\nand underscores only, 1-256 characters.\n",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_-]{1,256}$",
              "example": "op_12345"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Operator profile.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperatorProfileResponse"
                },
                "example": {
                  "operator_id": "op_12345",
                  "domain": "healthcare",
                  "created_at": "2026-02-14T17:05:00.000Z",
                  "last_interaction_at": "2026-04-22T08:58:02.118Z",
                  "profile": {
                    "interactions_scored": 312,
                    "mean_jis": 73.5,
                    "current_jis": 74.2,
                    "trend": "stable",
                    "classification": "adequate",
                    "dimension_means": {
                      "deferral_resistance": 70.4,
                      "error_detection_capability": 75.1,
                      "independent_performance": 72,
                      "deliberation_depth": 77.3,
                      "post_error_recalibration": 69.9,
                      "domain_confidence": 75.2,
                      "decision_autonomy": 73
                    },
                    "dimension_weakness": [],
                    "decay": {
                      "domain": "healthcare",
                      "alpha": 0.12,
                      "beta": 0.08,
                      "floor": 35,
                      "current_trend": "stable",
                      "projected_jis_30d": 71.3,
                      "projected_jis_90d": 66.8,
                      "mitigated_projected_jis_90d": 73.5
                    }
                  },
                  "jis_history": [
                    {
                      "jis": 70.1,
                      "timestamp": "2026-03-22T09:14:00.000Z"
                    },
                    {
                      "jis": 72.4,
                      "timestamp": "2026-04-01T09:14:00.000Z"
                    },
                    {
                      "jis": 74.2,
                      "timestamp": "2026-04-22T08:58:02.118Z"
                    }
                  ],
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/organization/dashboard": {
      "get": {
        "tags": [
          "Organization"
        ],
        "summary": "Get organization dashboard",
        "description": "Returns the aggregate dashboard for the organization identified by the\ncaller's API key: distribution of JIS scores across operators,\norganization-level compliance status, and alert counts.\n",
        "operationId": "getOrgDashboard",
        "responses": {
          "200": {
            "description": "Organization dashboard.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgDashboardResponse"
                },
                "example": {
                  "organization": "Example Hospital Group",
                  "domain": "healthcare",
                  "tier": "L2",
                  "dashboard": {
                    "operator_count": 42,
                    "mean_org_jis": 71.4,
                    "distribution": {
                      "exemplary": 4,
                      "proficient": 18,
                      "adequate": 13,
                      "at_risk": 6,
                      "impaired": 1,
                      "non_functional": 0
                    },
                    "org_compliance_status": "at_risk",
                    "weakest_dimensions": [
                      "deferral_resistance",
                      "error_detection_capability"
                    ],
                    "operators_below_60_pct": 14.3,
                    "operators_below_40_count": 1
                  },
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/maintenance/recommend": {
      "post": {
        "tags": [
          "Maintenance"
        ],
        "summary": "Recommend maintenance intervention",
        "description": "Returns the recommended adaptive-calibration intervention for an operator:\ncalibration injection, recommendation withholding, unranked presentation,\nor combinations, calibrated to their current JIS and per-dimension scores.\nMaintenance is adaptive by design; operators cannot distinguish a\nmaintenance interaction from a normal interaction in real time.\n",
        "operationId": "recommendMaintenance",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MaintenanceRequest"
              },
              "example": {
                "operator_id": "op_12345"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Maintenance recommendation.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MaintenanceResponse"
                },
                "example": {
                  "recommendation": {
                    "operator_id": "op_12345",
                    "current_jis": 58.9,
                    "trend": "declining",
                    "domain": "healthcare",
                    "trigger_intervention": true,
                    "intervention_type": "targeted_dimension_recovery",
                    "urgency": "moderate",
                    "rationale": "error_detection_capability < 60 and declining trend over last 30d.",
                    "compliance": {
                      "article_14_status": "at_risk",
                      "band": "at_risk",
                      "notes": "Below minimum-adequate threshold; schedule supervised recalibration."
                    },
                    "decay_projection": {
                      "domain": "healthcare",
                      "alpha": 0.12,
                      "beta": 0.08,
                      "floor": 35,
                      "current_trend": "declining",
                      "projected_jis_30d": 54.1,
                      "projected_jis_90d": 47.3,
                      "mitigated_projected_jis_90d": 60
                    },
                    "exercises": [
                      {
                        "type": "supervised_session",
                        "duration_minutes": 30,
                        "count": 4,
                        "frequency": "weekly",
                        "description": "Supervised error-injection sessions targeting error_detection_capability."
                      }
                    ]
                  },
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidJSON"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedBodyAuth"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/compliance/report": {
      "get": {
        "tags": [
          "Compliance"
        ],
        "summary": "Generate Article 14 compliance report",
        "description": "Generates and persists an EU AI Act Article 14 compliance report for the\ncaller's organization. Reports summarize organization-wide JIS\ndistribution, per-operator status, incident correlation, and the overall\nArticle 14 oversight posture.\n",
        "operationId": "getComplianceReport",
        "responses": {
          "200": {
            "description": "Compliance report generated.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComplianceReportResponse"
                },
                "example": {
                  "report": {
                    "report_id": "rpt_2026-04-22_0001",
                    "generated_at": "2026-04-22T09:14:12.004Z",
                    "organization": "Example Hospital Group",
                    "domain": "healthcare",
                    "overall_status": "at_risk",
                    "operators_summary": {
                      "total": 42,
                      "below_60_count": 6,
                      "below_60_pct": 14.3,
                      "below_40_count": 1
                    },
                    "dimensions_below_threshold": [
                      "deferral_resistance",
                      "error_detection_capability"
                    ],
                    "regulatory_framework": "EU AI Act Article 14 (high-risk AI, human oversight)"
                  },
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/key/rotate": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Self-serve API key rotation",
        "description": "Generates a new `ck_live_<26-char-Crockford-base32>` key for the caller's\norganization, hashes it with the server-side pepper, atomically updates\n`organizations.api_key_hash` + `api_key_prefix` + `api_key_rotated_at`,\nincrements `api_key_version`, and nulls any legacy plaintext `api_key`.\n**The new key is returned exactly once.** Store it immediately; there is\nno way to recover it after the response is discarded. Writes a\n`KEY_ROTATED` audit event.\n",
        "operationId": "adminKeyRotate",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Rotation takes no body parameters. An empty JSON object `{}` is\naccepted and recommended for clients that always send a body.\n",
                "example": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key rotated. New key returned exactly once.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminKeyRotateResponse"
                },
                "example": {
                  "new_api_key": "ck_live_H4R6Y2M9Q3K1Z8B5N7P0C4D2F6",
                  "prefix": "ck_live_",
                  "rotated_at": "2026-04-22T09:14:12.004Z",
                  "warning": "This is the ONLY time the new key will be shown. Store it securely.",
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidJSON"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/key/revoke": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Self-serve revocation",
        "description": "Sets `organizations.active = 0` for the caller's organization. All future\nrequests return `401 UNAUTHORIZED` until COHESION support reactivates the\norganization. Writes a `KEY_REVOKED` audit event. Use this when the key\nis believed compromised and you cannot immediately rotate; rotation\n(`POST /v1/admin/key/rotate`) is the preferred remediation when the\ncompromise is confined.\n",
        "operationId": "adminKeyRevoke",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Revocation takes no body parameters. An empty JSON object `{}` is\naccepted.\n",
                "example": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Organization revoked. All future requests will 401.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminKeyRevokeResponse"
                },
                "example": {
                  "revoked": true,
                  "org_id": "org_5f3c1a",
                  "revoked_at": "2026-04-22T09:14:12.004Z",
                  "note": "Organization is now inactive. All future requests will 401. Contact support to reactivate.",
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidJSON"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/audit-log": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "Retrieve own-org audit events",
        "description": "Returns audit events for the caller's organization, newest first. Every\nauth outcome, key rotation, key revocation, and scheduled cron run is\nrecorded here. Strictly scoped to the authenticated `org_id`; cannot\nread other organizations' events even if filter values would match.\n",
        "operationId": "adminAuditLog",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "event_type",
            "in": "query",
            "required": false,
            "description": "Filter to a single event type. Must be one of the whitelisted values\nenforced server-side (see `AuditEventType`). Unknown values return\n`422 VALIDATION_FAILED`.\n",
            "schema": {
              "$ref": "#/components/schemas/AuditEventType"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "ISO-8601 timestamp. Only events at or after this time are returned.",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-04-15T00:00:00Z"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "ISO-8601 timestamp. Only events at or before this time are returned.",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-04-22T23:59:59Z"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of events to return. Capped at 500.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audit events (newest first).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminAuditLogResponse"
                },
                "example": {
                  "events": [
                    {
                      "id": 10427,
                      "timestamp": "2026-04-22T09:14:12.004Z",
                      "event_type": "KEY_ROTATED",
                      "api_key_prefix": "ck_live_",
                      "path": "/v1/admin/key/rotate",
                      "method": "POST",
                      "status": 200,
                      "request_id": "7c2bd4de00a1b921",
                      "detail": "old_prefix=ck_live_"
                    },
                    {
                      "id": 10419,
                      "timestamp": "2026-04-22T08:58:02.118Z",
                      "event_type": "AUTH_SUCCESS",
                      "api_key_prefix": "ck_live_",
                      "path": "/v1/score",
                      "method": "POST",
                      "status": 200,
                      "request_id": "3ab901e771d40c12",
                      "detail": null
                    }
                  ],
                  "count": 2,
                  "filters": {
                    "event_type": null,
                    "since": null,
                    "until": null,
                    "limit": 100
                  },
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/score/{session_id}/commit": {
      "post": {
        "tags": [
          "Scoring"
        ],
        "summary": "Commit a provisional score",
        "description": "Finalize a provisional /v1/score result. Looks up the latest\nuncommitted row for (org_id, session_id), updates the decision\n+ modification_extent + telemetry fields, recomputes JIS, persists\ndimensions, and returns the envelope with `committed=true` and\n`commit_fingerprint=sha256:<hex>`. If the row was already committed,\nreturns 200 with the stored envelope when fingerprints match, or\n409 ALREADY_COMMITTED when they diverge. session_id must match\n`^[A-Za-z0-9_-]{1,256}$`.\n",
        "operationId": "scoreCommit",
        "parameters": [
          {
            "in": "path",
            "name": "session_id",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,256}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "decision",
                  "modification_extent"
                ],
                "properties": {
                  "decision": {
                    "$ref": "#/components/schemas/Decision"
                  },
                  "modification_extent": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "hover_events": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "scroll_depth": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "alternative_views_checked": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "outcome_correct": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Commit succeeded (or fingerprint match on already-committed row).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScoreResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No provisional row exists for the given org_id and session_id pair."
          },
          "409": {
            "description": "Already committed with a divergent fingerprint."
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/audit-log/export": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "Export own-org audit-log events as ND-JSON",
        "description": "Streams audit_log events for the authenticated org as newline-\ndelimited JSON. Emits an X-COHESION-Export-Signature: sha256=<hex>\nHMAC integrity header computed over the response body. Reuses\ncanonical auth, 80 ms timing floor, layer-2 per-key rate limit,\nand audit-log writes. Cursor pagination via `since` (ISO-8601)\nand `limit` (clamped to 500, never rejected).\n",
        "operationId": "adminAuditLogExport",
        "parameters": [
          {
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "ISO-8601 lower bound on `timestamp`. Inclusive."
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ND-JSON stream; X-COHESION-Export-Signature header carries integrity HMAC.",
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/webhook/register": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Register a webhook endpoint",
        "description": "Register a HTTPS receiver for outbound score-event webhooks.\nSSRF guards reject http:// in production, localhost, RFC1918,\nlink-local (incl. cloud metadata 169.254.169.254), multicast,\nIPv6 loopback / unique-local / link-local, IPv4-mapped IPv6,\n.internal/.local TLDs, and userinfo-bearing URLs. The secret\nis stored as SHA-256(secret || pepper); the same hash signs\noutbound HMAC headers.\n",
        "operationId": "adminWebhookRegister",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "secret"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048
                  },
                  "secret": {
                    "type": "string",
                    "minLength": 16,
                    "description": "Plaintext shared secret; only the hash is stored at rest."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Endpoint registered. Returns endpoint_id, url, active, created_at, request_id, timestamp."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/webhook/list": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "List the org's registered webhook endpoints",
        "operationId": "adminWebhookList",
        "responses": {
          "200": {
            "description": "Returns the endpoints array with id, url, active, created_at."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/admin/webhook/{webhook_id}": {
      "delete": {
        "tags": [
          "Admin"
        ],
        "summary": "Soft-delete a webhook endpoint",
        "description": "Sets `active = 0`. Future deliveries are not attempted.",
        "operationId": "adminWebhookDelete",
        "parameters": [
          {
            "in": "path",
            "name": "webhook_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoint deactivated."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Endpoint not found or already deactivated."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/assessments": {
      "post": {
        "tags": [
          "Demo"
        ],
        "summary": "Submit a public demo run",
        "description": "Accepts a completed public-demo assessment from the `/demo/` interactive\nexperience and persists it to `demo_assessments`. Unauthenticated:\nthere is no API key on this route. Only Layer 1 per-IP rate limiting\napplies. Body cap: 256 KB (tightened from 2 MB on 2026-04-29 per\nC2 P1-6). Returns a shareable URL the demo UI renders.\n",
        "operationId": "submitAssessment",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssessmentSubmitRequest"
              },
              "example": {
                "sessionId": "sess_2026-04-22_demo_0741",
                "createdAt": "2026-04-22T09:14:12.004Z",
                "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4) Safari/17.4",
                "domain": "healthcare",
                "score": {
                  "jis": 72.8,
                  "dimensions": {
                    "deferral_resistance": 68.1,
                    "error_detection_capability": 74.4,
                    "independent_performance": 71,
                    "deliberation_depth": 76.2,
                    "post_error_recalibration": 70.5,
                    "domain_confidence": 73.9,
                    "decision_autonomy": 75
                  }
                },
                "records": [
                  {
                    "scenario_id": "hc_01",
                    "decision": "modified",
                    "time_to_decision_ms": 14200,
                    "outcome_correct": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Assessment persisted; share URL returned.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssessmentSubmitResponse"
                },
                "example": {
                  "ok": true,
                  "sessionId": "sess_2026-04-22_demo_0741",
                  "shareUrl": "https://cohesionauth.com/demo/?share=sess_2026-04-22_demo_0741",
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidJSON"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/assessments/{sessionId}": {
      "get": {
        "tags": [
          "Demo"
        ],
        "summary": "Retrieve a shared demo run",
        "description": "Returns a previously submitted public-demo assessment by its session\nidentifier. Unauthenticated; safe to link-share. 404 if the session does\nnot exist.\n",
        "operationId": "getAssessment",
        "security": [],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "Session identifier originally supplied on `POST /assessments`.\nAlphanumeric, hyphens, and underscores only, 1-128 characters.\n",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_-]{1,128}$",
              "example": "sess_2026-04-22_demo_0741"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Demo assessment retrieved.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/XRequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssessmentGetResponse"
                },
                "example": {
                  "sessionId": "sess_2026-04-22_demo_0741",
                  "createdAt": "2026-04-22T09:14:12.004Z",
                  "domain": "healthcare",
                  "jis": 72.8,
                  "dimensions": {
                    "deferral_resistance": 68.1,
                    "error_detection_capability": 74.4,
                    "independent_performance": 71,
                    "deliberation_depth": 76.2,
                    "post_error_recalibration": 70.5,
                    "domain_confidence": 73.9,
                    "decision_autonomy": 75
                  },
                  "records": [
                    {
                      "scenario_id": "hc_01",
                      "decision": "modified",
                      "time_to_decision_ms": 14200,
                      "outcome_correct": true
                    }
                  ],
                  "receivedAt": "2026-04-22T09:14:12.004Z",
                  "request_id": "7c2bd4de00a1b921",
                  "timestamp": "2026-04-22T09:14:12.004Z"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/org/create": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Provision a new organization",
        "description": "Master-key endpoint. Creates a new `organizations` row plus its first\nper-org API key. Required header `Idempotency-Key` for replay safety.\nSee scoring-api/CLAUDE.md 2026-05-02 carve-out.\n",
        "operationId": "adminOrgCreate",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Organization created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/billing/org/{org_id}/suspend": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Suspend an org for a billing reason",
        "description": "Master-key endpoint called by `payment-worker` on quota-cross,\ncancellation, refund, or dispute. Sets `organizations.active = 0` and\naudit-logs `ADMIN_BILLING_SUSPEND`. See scoring-api/CLAUDE.md\n2026-05-02 carve-out.\n",
        "operationId": "adminBillingSuspend",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Org suspended.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/billing/org/{org_id}/rotate": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Rotate an org key on a billing event",
        "description": "Master-key endpoint called by `payment-worker` on subscription\nreactivation. Mints a new per-org API key and revokes the prior key.\nSee scoring-api/CLAUDE.md 2026-05-02 carve-out.\n",
        "operationId": "adminBillingRotate",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key rotated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/org/{org_id}/usage": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "Read org usage counters",
        "description": "Master-key endpoint used by `payment-worker` for the 5-minute quota\npoll. Read-only. See scoring-api/CLAUDE.md 2026-05-02 carve-out.\n",
        "operationId": "adminOrgUsage",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Usage counters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/org/{org_id}/suspend": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Operator-side suspend",
        "description": "Master-key endpoint for operator-initiated suspension. See\nscoring-api/CLAUDE.md 2026-05-02 carve-out.\n",
        "operationId": "adminOrgSuspend",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Org suspended.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/org/{org_id}/reactivate": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Operator-side reactivate",
        "description": "Master-key endpoint to reactivate a suspended org. See\nscoring-api/CLAUDE.md 2026-05-02 carve-out.\n",
        "operationId": "adminOrgReactivate",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Org reactivated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/org/{org_id}/force-rotate": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Operator-side force key rotate",
        "description": "Master-key endpoint. Rotates an org key bypassing per-org consent\npath. See scoring-api/CLAUDE.md 2026-05-02 carve-out.\n",
        "operationId": "adminOrgForceRotate",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key force-rotated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/org/{org_id}/force-revoke": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Operator-side force key revoke",
        "description": "Master-key endpoint. Revokes all keys on an org bypassing the\nper-org consent path. See scoring-api/CLAUDE.md 2026-05-02 carve-out.\n",
        "operationId": "adminOrgForceRevoke",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Keys revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/admin/alerts/{alert_id}/ack": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Acknowledge an active alert",
        "description": "Master-key endpoint. Marks an alerts row as acknowledged. See\nscoring-api/CLAUDE.md 2026-05-02 carve-out.\n",
        "operationId": "adminAlertAck",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Alert acknowledged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/decision/score": {
      "post": {
        "tags": [
          "DRS"
        ],
        "summary": "Score a high-stakes AI-augmented decision",
        "description": "Per-org X-API-Key auth + RBAC. Computes pre-AI and post-AI DRS,\nwrites to `ai_decision_log` with HMAC chaining. See\nscoring-api/CLAUDE.md 2026-05-06 carve-out.\n",
        "operationId": "decisionScore",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Decision scored.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled (stage-flag gated)."
          }
        }
      }
    },
    "/v1/decision/replay/{ai_decision_log_id}": {
      "get": {
        "tags": [
          "DRS"
        ],
        "summary": "Audit-replay a prior decision",
        "description": "Read-only re-execution against original `policy_version_id` +\n`input_hash` + `output_hash`. Writes a `replayed_for_audit` row.\nSee scoring-api/CLAUDE.md 2026-05-06 carve-out.\n",
        "operationId": "decisionReplay",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "parameters": [
          {
            "name": "ai_decision_log_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Replay result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/admin/compliance-profile": {
      "post": {
        "tags": [
          "Admin",
          "DRS"
        ],
        "summary": "Write a new org compliance profile version",
        "description": "Master-key endpoint. Inserts a new `org_compliance_profile_versions`\nrow and closes the prior row's `effective_until`. See\nscoring-api/CLAUDE.md 2026-05-06 carve-out.\n",
        "operationId": "adminComplianceProfile",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Profile version written.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/admin/override-patterns": {
      "get": {
        "tags": [
          "Admin",
          "DRS"
        ],
        "summary": "Reviewer override pattern analytics",
        "description": "Master-key endpoint. Z-score-based reviewer flagging across a rolling\nwindow. See scoring-api/CLAUDE.md 2026-05-06 carve-out.\n",
        "operationId": "adminOverridePatterns",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "parameters": [
          {
            "name": "org_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "30d"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Override-pattern report.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/admin/users": {
      "post": {
        "tags": [
          "Admin",
          "DRS"
        ],
        "summary": "Upsert an org user role",
        "description": "Master-key endpoint. Insert or update one row in `org_user_roles`.\nSee scoring-api/CLAUDE.md 2026-05-06 carve-out.\n",
        "operationId": "adminUsersUpsert",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Role written.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      },
      "get": {
        "tags": [
          "Admin",
          "DRS"
        ],
        "summary": "List org user roles",
        "description": "Master-key endpoint. Returns roles for the org identified by the\nmaster-key scope. See scoring-api/CLAUDE.md 2026-05-06 carve-out.\n",
        "operationId": "adminUsersList",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "parameters": [
          {
            "name": "org_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Role list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      },
      "delete": {
        "tags": [
          "Admin",
          "DRS"
        ],
        "summary": "Remove an org user role",
        "description": "Master-key endpoint. Removes one row from `org_user_roles`. See\nscoring-api/CLAUDE.md 2026-05-06 carve-out.\n",
        "operationId": "adminUsersDelete",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Role removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/admin/audit/verify-chain": {
      "get": {
        "tags": [
          "Admin",
          "DRS"
        ],
        "summary": "Verify HMAC chain over ai_decision_log slice",
        "description": "Master-key endpoint. Runs `lib/log-chain.js::verifyChain` over a\nslice; emits `audit_chain_break_detected` reason code on failure.\nSee scoring-api/CLAUDE.md 2026-05-06 carve-out.\n",
        "operationId": "adminVerifyChain",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "parameters": [
          {
            "name": "org_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Chain verification result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "Chain break detected; export fail-closed."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/decision/review": {
      "post": {
        "tags": [
          "Reviewer"
        ],
        "summary": "Reviewer submits a human action on a flagged decision",
        "description": "Auth: per-org X-API-Key OR reviewer JWT; RBAC scope `submit_review`.\nCalls `recordHumanAction`. See scoring-api/CLAUDE.md 2026-05-08\ncarve-out.\n",
        "operationId": "decisionReview",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Review recorded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/auth/magic-link/request": {
      "post": {
        "tags": [
          "Reviewer",
          "Auth"
        ],
        "summary": "Request a reviewer magic-link",
        "description": "Public, rate-limited. Returns 200 regardless of email existence to\nprevent enumeration. See scoring-api/CLAUDE.md 2026-05-08 carve-out.\n",
        "operationId": "magicLinkRequest",
        "security": [],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Magic-link processed (response is identical whether the email exists or not).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/auth/magic-link/redeem": {
      "post": {
        "tags": [
          "Reviewer",
          "Auth"
        ],
        "summary": "Redeem a reviewer magic-link",
        "description": "Public. Verifies HMAC, sets `redeemed_at` atomically, returns\nshort-lived JWT. 401 on replay. See scoring-api/CLAUDE.md 2026-05-08\ncarve-out.\n",
        "operationId": "magicLinkRedeem",
        "security": [],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JWT minted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/decision/queue": {
      "get": {
        "tags": [
          "Reviewer"
        ],
        "summary": "Reviewer queue (tenant-scoped)",
        "description": "Reviewer JWT auth. Tenant-scoped on JWT `org_id`. Cursor-paginated.\nNever accepts request-supplied `org_id`. See scoring-api/CLAUDE.md\n2026-05-08 carve-out.\n",
        "operationId": "decisionQueue",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Queue page.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/decision/{ai_decision_log_id}": {
      "get": {
        "tags": [
          "Reviewer"
        ],
        "summary": "Reviewer decision detail",
        "description": "Reviewer JWT auth. Tenant cross-org returns 404 (info-leak\nprevention; not 403). 80 ms timing floor verified <5 ms vs\ndecision-not-found. See scoring-api/CLAUDE.md 2026-05-08 carve-out.\n",
        "operationId": "decisionDetail",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "parameters": [
          {
            "name": "ai_decision_log_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Decision detail.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/admin/reviewers": {
      "post": {
        "tags": [
          "Admin",
          "Reviewer"
        ],
        "summary": "Upsert a reviewer account",
        "description": "Customer-tenant X-API-Key with `manage_reviewers` scope OR\n`customer_admin` role. Never founder-managed. See\nscoring-api/CLAUDE.md 2026-05-08 carve-out.\n",
        "operationId": "adminReviewersUpsert",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reviewer written.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      },
      "get": {
        "tags": [
          "Admin",
          "Reviewer"
        ],
        "summary": "List reviewer accounts",
        "description": "Customer-tenant X-API-Key with `manage_reviewers` scope OR\n`customer_admin` role. Tenant-scoped on the X-API-Key's org. See\nscoring-api/CLAUDE.md 2026-05-08 carve-out.\n",
        "operationId": "adminReviewersList",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "responses": {
          "200": {
            "description": "Reviewer list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      },
      "delete": {
        "tags": [
          "Admin",
          "Reviewer"
        ],
        "summary": "Remove a reviewer account",
        "description": "Customer-tenant X-API-Key with `manage_reviewers` scope OR\n`customer_admin` role. Tenant-scoped on the X-API-Key's org. See\nscoring-api/CLAUDE.md 2026-05-08 carve-out.\n",
        "operationId": "adminReviewersDelete",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reviewer removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "DRS engine not enabled."
          }
        }
      }
    },
    "/v1/admin/methodology-annex/generate": {
      "post": {
        "tags": [
          "Admin",
          "Annex"
        ],
        "summary": "Generate signed Methodology Annex PDF",
        "description": "Master-key endpoint. Required `Idempotency-Key` header. Wraps PDF\nrender + R2 PUT + success audit in `withAdminIdempotency`. Email\nsend via Resend AFTER success audit; transport failure returns 200\nwith `email_sent:false`. See scoring-api/CLAUDE.md 2026-05-11\ncarve-out.\n",
        "operationId": "methodologyAnnexGenerate",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Annex generated (PDF stored in R2; email send result reported).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "Methodology Annex not enabled."
          }
        }
      }
    },
    "/v1/admin/methodology-annex/verify": {
      "post": {
        "tags": [
          "Admin",
          "Annex"
        ],
        "summary": "Verify a Methodology Annex HMAC + content hash",
        "description": "Master-key endpoint. READ-ONLY (no D1 mutation, no R2 mutation).\nRecomputes HMAC and optional sha256 with constant-time compare.\nReturns `computed_hmac_prefix` (12 hex chars only). See\nscoring-api/CLAUDE.md 2026-05-12 carve-out.\n",
        "operationId": "methodologyAnnexVerify",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "Demo API not enabled."
          }
        }
      }
    },
    "/v1/admin/demo/idempotency": {
      "post": {
        "tags": [
          "Admin",
          "Demo"
        ],
        "summary": "Demo-companion idempotency dispatch",
        "description": "Master-key endpoint. Closed-allowlist namespace dispatch over the\nexisting `admin_action_idempotency` table. See scoring-api/CLAUDE.md\n2026-05-12 carve-out.\n",
        "operationId": "demoIdempotency",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Dispatch result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "Demo API not enabled."
          }
        }
      }
    },
    "/v1/telemetry/ai-call-observed": {
      "post": {
        "tags": [
          "Telemetry"
        ],
        "summary": "SDK-emitted client-side AI-call observation",
        "description": "Per-org X-API-Key auth. INSERT OR IGNORE into `ai_call_observations`.\nDedupe key is UNIQUE(org_id, request_id). Returns 202. See\nscoring-api/CLAUDE.md 2026-05-13 Coverage Lane carve-out.\n",
        "operationId": "telemetryAiCallObserved",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "request_id"
                ],
                "properties": {
                  "request_id": {
                    "type": "string"
                  },
                  "operator_id": {
                    "type": "string"
                  },
                  "decision_category": {
                    "type": "string"
                  },
                  "observed_at": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Observation accepted (or deduped).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "Coverage telemetry not enabled."
          }
        }
      }
    },
    "/v1/organization/coverage": {
      "get": {
        "tags": [
          "Organization",
          "Telemetry"
        ],
        "summary": "DRS instrumentation-coverage dial",
        "description": "Per-org X-API-Key auth. LEFT JOIN of `ai_call_observations` against\nterminal `ai_decision_log` events over a configurable window.\nReturns `coverage_pct: null` on empty-org rather than div-by-zero.\nSee scoring-api/CLAUDE.md 2026-05-13 Coverage Lane carve-out.\n",
        "operationId": "organizationCoverage",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "x-implementation-status": "pending",
        "parameters": [
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "7d",
                "30d",
                "90d"
              ],
              "default": "7d"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Coverage dial.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "Coverage telemetry not enabled."
          }
        }
      }
    },
    "/v1/auth/sso/saml/initiate": {
      "post": {
        "tags": [
          "Auth",
          "SSO"
        ],
        "summary": "Begin SAML 2.0 SSO flow",
        "description": "Public. Loads `sso_configurations` row, calls\n`lib/sso-saml.js::initiateSaml`, returns IdP action URL + signed\nSAMLRequest + relay state. See scoring-api/CLAUDE.md 2026-05-13\nSSO Lane carve-out.\n",
        "operationId": "ssoSamlInitiate",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "org_id"
                ],
                "properties": {
                  "org_id": {
                    "type": "string"
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SAML initiation payload.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "SSO not enabled."
          }
        }
      }
    },
    "/v1/auth/sso/saml/acs": {
      "post": {
        "tags": [
          "Auth",
          "SSO"
        ],
        "summary": "SAML 2.0 Assertion Consumer Service",
        "description": "Public HTTP-POST ACS endpoint. Decodes + validates SAML Response\nvia `lib/sso-saml.js::consumeSaml`. On success returns reviewer JWT.\nSee scoring-api/CLAUDE.md 2026-05-13 SSO Lane carve-out.\n",
        "operationId": "ssoSamlAcs",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "SAMLResponse"
                ],
                "properties": {
                  "SAMLResponse": {
                    "type": "string"
                  },
                  "RelayState": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSO succeeded; reviewer JWT minted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "SSO not enabled."
          }
        }
      }
    },
    "/v1/auth/sso/oidc/initiate": {
      "post": {
        "tags": [
          "Auth",
          "SSO"
        ],
        "summary": "Begin OIDC Authorization Code + PKCE flow",
        "description": "Public. Calls `lib/sso-oidc.js::initiateOidc`; returns\nauthorization URL + state nonce. See scoring-api/CLAUDE.md\n2026-05-13 SSO Lane carve-out.\n",
        "operationId": "ssoOidcInitiate",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "org_id"
                ],
                "properties": {
                  "org_id": {
                    "type": "string"
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OIDC initiation payload.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "SSO not enabled."
          }
        }
      }
    },
    "/v1/auth/sso/oidc/callback": {
      "get": {
        "tags": [
          "Auth",
          "SSO"
        ],
        "summary": "OIDC redirect-URI handler",
        "description": "Public. Atomic state consume via `DELETE … RETURNING`. Calls\n`lib/sso-oidc.js::callbackOidc`. On success returns reviewer JWT.\nSee scoring-api/CLAUDE.md 2026-05-13 SSO Lane carve-out.\n",
        "operationId": "ssoOidcCallback",
        "security": [],
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SSO succeeded; reviewer JWT minted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "SSO not enabled."
          }
        }
      }
    },
    "/v1/admin/org/{org_id}/sso/configure": {
      "post": {
        "tags": [
          "Admin",
          "SSO"
        ],
        "summary": "Configure org SSO (SAML or OIDC)",
        "description": "Master-key endpoint. Required `Idempotency-Key` header. Full-replace\nupsert. OIDC `client_secret` is AES-GCM encrypted via\n`lib/sso-oidc.js::encryptClientSecret` before persistence. See\nscoring-api/CLAUDE.md 2026-05-13 SSO Lane carve-out.\n",
        "operationId": "adminSsoConfigure",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "org_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "protocol"
                ],
                "properties": {
                  "protocol": {
                    "type": "string",
                    "enum": [
                      "saml",
                      "oidc"
                    ]
                  },
                  "entity_id": {
                    "type": "string"
                  },
                  "sso_url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "x509_cert": {
                    "type": "string"
                  },
                  "oidc_client_id": {
                    "type": "string"
                  },
                  "oidc_client_secret": {
                    "type": "string"
                  },
                  "oidc_issuer": {
                    "type": "string",
                    "format": "uri"
                  },
                  "attribute_mapping": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSO configuration written.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "description": "SSO not enabled."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Per-organization API key. Used for all GET requests. Keys are ≥32-byte\nURL-safe strings and are revocable from the COHESION admin console. See the\n[key rotation runbook](https://github.com/cohesion/scoring-api/blob/main/README.md#key-rotation).\n"
      },
      "apiKeyBody": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key-Body-Equivalent",
        "description": "**DEPRECATED 2026-04-17, sunset 2026-07-15.** POST endpoints also accept\nthe per-organization API key as the `api_key` field inside the JSON\nrequest body. Exactly one of `X-API-Key` or `api_key` must be supplied.\nBody-auth callers receive `Deprecation: true`, `Sunset`, and `Link`\nresponse headers. (This scheme is declared as a header for OpenAPI\ntooling compatibility; there is no literal `X-API-Key-Body-Equivalent`\nheader; the server reads the `api_key` body field on documented POST\nroutes.)\n"
      }
    },
    "headers": {
      "XRequestID": {
        "description": "Unique identifier for this request. Echoed in every response body and the\n`X-Request-ID` response header. Log it with every support ticket.\n",
        "schema": {
          "type": "string",
          "pattern": "^[a-f0-9]{16,}$",
          "example": "7c2bd4de00a1b921"
        }
      },
      "Deprecation": {
        "description": "RFC 9745 marker. Present (`true`) on every response whose request used\na deprecated input surface (currently: `api_key` in the JSON body\ninstead of the `X-API-Key` header). Always paired with `Sunset` and\n`Link` headers below.\n",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ]
        },
        "example": "true"
      },
      "Sunset": {
        "description": "RFC 8594 absolute date after which the deprecated surface stops working.\nFixed at `Wed, 15 Jul 2026 00:00:00 GMT` for body-form auth.\n",
        "schema": {
          "type": "string"
        },
        "example": "Wed, 15 Jul 2026 00:00:00 GMT"
      },
      "LinkDeprecation": {
        "description": "RFC 8288 link to the deprecation/migration documentation, with\n`rel=\"deprecation\"`. Lets clients programmatically discover the\nupgrade docs.\n",
        "schema": {
          "type": "string"
        },
        "example": "<https://cohesionauth.com/api/>; rel=\"deprecation\"; type=\"text/html\""
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying. Always an integer ≥ 1.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "example": 60
        }
      }
    },
    "parameters": {},
    "schemas": {
      "Domain": {
        "type": "string",
        "description": "High-risk AI-oversight domain the operator works in.",
        "enum": [
          "healthcare",
          "aviation",
          "financial",
          "legal",
          "pharmaceutical",
          "general"
        ]
      },
      "Decision": {
        "type": "string",
        "description": "Classification of the operator's decision relative to the AI recommendation.\nAdded 2026-04-29 (V2 founding-notes pivot): `defer` for active-incident\nand other deferred-judgment paths.\n",
        "enum": [
          "accepted",
          "modified",
          "rejected",
          "independent",
          "defer"
        ]
      },
      "ScenarioType": {
        "type": "string",
        "description": "Classification of the scenario presented to the operator. `trap` and\n`split` scenarios are adaptive-calibration events used for calibration.\n",
        "enum": [
          "standard",
          "independent",
          "trap",
          "split"
        ]
      },
      "Dimension": {
        "type": "string",
        "description": "One of the seven judgment dimensions.",
        "enum": [
          "deferral_resistance",
          "error_detection_capability",
          "independent_performance",
          "deliberation_depth",
          "post_error_recalibration",
          "domain_confidence",
          "decision_autonomy"
        ]
      },
      "Interaction": {
        "type": "object",
        "description": "A single behavioural record of one human-AI interaction. Every field is\nrequired. The ten fields together capture the behavioural signature the\nJIS engine needs to score the interaction.\n",
        "required": [
          "ai_recommendation_presented",
          "time_to_decision_ms",
          "decision",
          "modification_extent",
          "ai_available",
          "scenario_type",
          "outcome_correct",
          "hover_events",
          "scroll_depth",
          "alternative_views_checked"
        ],
        "properties": {
          "ai_recommendation_presented": {
            "type": "boolean",
            "description": "True if an AI recommendation was shown to the operator."
          },
          "time_to_decision_ms": {
            "type": "integer",
            "minimum": 0,
            "description": "Milliseconds from the AI output being presented to the operator's decision."
          },
          "decision": {
            "$ref": "#/components/schemas/Decision"
          },
          "modification_extent": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 1,
            "description": "0.0 = accepted verbatim, 1.0 = completely rewritten. Meaningful only\nwhen `decision` is `modified`.\n"
          },
          "ai_available": {
            "type": "boolean",
            "description": "True if the AI system was available at the time of decision."
          },
          "scenario_type": {
            "$ref": "#/components/schemas/ScenarioType"
          },
          "outcome_correct": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Ground-truth correctness of the operator's decision. `null` if\nground truth is unknown at scoring time.\n"
          },
          "hover_events": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of hover interactions the operator triggered on AI-output metadata."
          },
          "scroll_depth": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 1,
            "description": "Fraction of the AI-output panel the operator actually scrolled through."
          },
          "alternative_views_checked": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of alternative views, sources, or reference sections the operator opened."
          },
          "decision_metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional operator-supplied decision context (V2 trust blocker #3,\nadded 2026-04-29). Validated as a JSON object with serialized\nlength ≤ 2048 bytes. Persisted as TEXT in the interactions row.\nUse cases: rationale, override-reason tags, downstream-system\nreferences the operator wants to attach to this decision.\n",
            "example": {
              "rationale": "overrode AI recommendation per legal review",
              "tags": [
                "legal-review",
                "override"
              ]
            }
          }
        }
      },
      "ScoreRequest": {
        "type": "object",
        "required": [
          "session_id",
          "operator_id",
          "domain",
          "interaction"
        ],
        "description": "Body for `POST /v1/score`. The `api_key` field is deprecated and optional;\nprefer the `X-API-Key` header. Exactly one of header or body auth must be\nsupplied.\n",
        "properties": {
          "api_key": {
            "type": "string",
            "maxLength": 256,
            "deprecated": true,
            "x-deprecated-as-of": "2026-04-17",
            "x-sunset-date": "2026-07-15",
            "description": "**DEPRECATED 2026-04-17, sunset 2026-07-15.** Pass the key in the\n`X-API-Key` header instead. Body-form auth still works during the\nsunset window but emits `Deprecation: true` and\n`Sunset: Wed, 15 Jul 2026 00:00:00 GMT` response headers.\n"
          },
          "session_id": {
            "type": "string",
            "maxLength": 256,
            "description": "Client-generated session identifier. Scoped to the operator."
          },
          "operator_id": {
            "type": "string",
            "maxLength": 256,
            "pattern": "^[a-zA-Z0-9_-]{1,256}$",
            "description": "Organization-scoped operator identifier."
          },
          "domain": {
            "$ref": "#/components/schemas/Domain"
          },
          "interaction": {
            "$ref": "#/components/schemas/Interaction"
          }
        }
      },
      "ScoreResponse": {
        "type": "object",
        "required": [
          "request_id",
          "timestamp"
        ],
        "description": "Response envelope for `POST /v1/score`. Two shapes share this schema:\n\n1. Standard scoring response (the common case) includes `jis`,\n   `displayed_jis`, `provisional`, `provisional_reason`, `dimensions`,\n   `decay_projection`, `compliance`, and `maintenance_recommendation`,\n   plus additive keys `mode`, `dimensions_computed`, and `role_tier`\n   introduced 2026-04-24.\n2. Skipped envelope (when `?mode_override=incident_frozen`) includes\n   `skipped: true`, `reason`, and `mode_override: \"incident_frozen\"`,\n   and omits `jis`, `dimensions`, `decay_projection`, `compliance`,\n   and `maintenance_recommendation`. Used when the caller signals that\n   the operator is in active incident containment and hover/scroll\n   behavior would mis-read as rubber-stamping.\n\nCycle 3 (2026-04-25): `displayed_jis` (spec §4.4 EWMA-smoothed),\n`provisional` (spec §4.3 minimum-data gate), and `provisional_reason`\nadded. `decay_projection` enriched with `decay_acceleration` per\nspec §6 second decay parameter.\n",
        "properties": {
          "jis": {
            "$ref": "#/components/schemas/JIS"
          },
          "displayed_jis": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/JIS"
              },
              {
                "type": "null"
              }
            ],
            "description": "Spec §4.4 normative: 30-day-half-life EWMA over the operator's\nhistory. This is the value cited by compliance reports. `null`\nwhen no usable history exists. SDK consumers should display this\nvalue alongside `jis` (the raw current-interaction score).\n"
          },
          "provisional": {
            "type": "boolean",
            "description": "Spec §4.3: `true` when the operator does not yet meet the\ncomposite-data gate (50 interactions OR 10 days of monitoring,\nwhichever first). Provisional scores MAY be displayed but MUST\nNOT be used for compliance, employment, or operational decisions.\n"
          },
          "provisional_reason": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable explanation of why the score is provisional, citing\nthe spec §4.3 gate. `null` when not provisional.\n"
          },
          "dimensions": {
            "$ref": "#/components/schemas/DimensionScores"
          },
          "decay_projection": {
            "$ref": "#/components/schemas/DecayProjection"
          },
          "compliance": {
            "$ref": "#/components/schemas/ComplianceEvaluation"
          },
          "maintenance_recommendation": {
            "$ref": "#/components/schemas/MaintenanceDecision"
          },
          "session_id": {
            "type": "string",
            "description": "Echo of the `session_id` from the request body."
          },
          "committed": {
            "type": "boolean",
            "description": "Whether this scoring row has been committed via\n`POST /v1/score/{session_id}/commit`. Always `false` on\n`/v1/score` responses; flips to `true` only through the commit\nendpoint.\n"
          },
          "mode": {
            "type": "string",
            "enum": [
              "full",
              "lite"
            ],
            "description": "Scoring mode used for this response. `full` scored all 7\ndimensions; `lite` scored D1 + D4 + D7 only. Defaults to `full`\nwhen no `?mode` or `X-Cohesion-Mode` was supplied.\n"
          },
          "dimensions_computed": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of the dimensions present in `dimensions`. For `full` mode:\nall 7 dimension names. For `lite` mode: `deferral_resistance`,\n`deliberation_depth`, `decision_autonomy`.\n"
          },
          "role_tier": {
            "type": "string",
            "enum": [
              "tier_1",
              "tier_2",
              "tier_3"
            ],
            "description": "Operator skill tier echoed from the request. Section 1 plumbs this\nthrough; tier-specific Adaptive Calibration deltas ship in\nSection 4. Defaults to `tier_1` when no `?role_tier` or\n`X-Cohesion-Role-Tier` was supplied.\n"
          },
          "cognition_probes": {
            "oneOf": [
              {
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "14-probe envelope per spec §7.8 (cluster 1-4 close, 2026-05-04).\nEach probe ships a structured-result shape (delta, classification,\nfired/unfired, components, etc.). Probe set in wire order:\n`counterfactual_delta`, `pre_commitment`, `omission_commission`,\n`verification_intensity`, `specification_gaming`,\n`asymmetric_decision_time`, `threshold_gaming`, `alert_fatigue`,\n`complacency_buildup`, `cascade_detector`, `slow_drift`,\n`response_set`, `regulatory_threshold_proximity`, `reaction_time_z`.\n`null` when the probe block fails as a whole — additive, never\nblocks the base /v1/score response. Per-probe error isolation is\na Sprint-2 carry-forward.\n"
          },
          "skipped": {
            "type": "boolean",
            "description": "Only present when `?mode_override=incident_frozen`. Signals that\nno JIS was computed for this interaction because the operator is\nin active containment. When `true`, `jis`, `dimensions`, and the\ncompliance/decay/maintenance fields are omitted.\n"
          },
          "reason": {
            "type": "string",
            "description": "Only present on skipped envelopes. Human-readable explanation for\nwhy JIS computation was paused.\n"
          },
          "mode_override": {
            "type": "string",
            "enum": [
              "incident_frozen"
            ],
            "description": "Only present on skipped envelopes. Echoes the override that\ntriggered the skip.\n"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ScoreBatchRequest": {
        "type": "object",
        "required": [
          "operator_id",
          "domain",
          "interactions"
        ],
        "description": "Body for `POST /v1/score/batch`. The `api_key` field is deprecated and\noptional; prefer the `X-API-Key` header.\n",
        "properties": {
          "api_key": {
            "type": "string",
            "maxLength": 256,
            "deprecated": true,
            "x-deprecated-as-of": "2026-04-17",
            "x-sunset-date": "2026-07-15",
            "description": "**DEPRECATED 2026-04-17, sunset 2026-07-15.** Use the `X-API-Key` header.\n"
          },
          "operator_id": {
            "type": "string",
            "maxLength": 256,
            "pattern": "^[a-zA-Z0-9_-]{1,256}$"
          },
          "session_id": {
            "type": "string",
            "maxLength": 256
          },
          "domain": {
            "$ref": "#/components/schemas/Domain"
          },
          "interactions": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/Interaction"
            }
          }
        }
      },
      "ScoreBatchResponse": {
        "type": "object",
        "required": [
          "results",
          "count",
          "operator_id",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchResultItem"
            }
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "operator_id": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BatchResultItem": {
        "type": "object",
        "required": [
          "jis",
          "dimensions",
          "decay_projection"
        ],
        "properties": {
          "jis": {
            "$ref": "#/components/schemas/JIS"
          },
          "displayed_jis": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/JIS"
              },
              {
                "type": "null"
              }
            ],
            "description": "Spec §4.4 EWMA value for this batch result. Each entry's EWMA\nwindow includes the preceding entries in the same batch, so\nresults late in the batch reflect more history.\n"
          },
          "dimensions": {
            "$ref": "#/components/schemas/DimensionScores"
          },
          "decay_projection": {
            "$ref": "#/components/schemas/DecayProjection"
          }
        }
      },
      "OperatorProfileResponse": {
        "type": "object",
        "required": [
          "operator_id",
          "domain",
          "profile",
          "jis_history",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "operator_id": {
            "type": "string"
          },
          "domain": {
            "$ref": "#/components/schemas/Domain"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_interaction_at": {
            "type": "string",
            "format": "date-time"
          },
          "profile": {
            "$ref": "#/components/schemas/OperatorProfile"
          },
          "displayed_jis": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/JIS"
              },
              {
                "type": "null"
              }
            ],
            "description": "Cycle 3.5 cascade #1: spec §4.4 EWMA-smoothed score over the\noperator's full history. The normative value for compliance\nreporting; raw per-interaction `computed_jis` is retained in\n`jis_history` for audit trail.\n"
          },
          "jis_history": {
            "type": "array",
            "description": "Sparkline points, ordered oldest → newest.",
            "items": {
              "type": "object",
              "required": [
                "jis",
                "timestamp"
              ],
              "properties": {
                "jis": {
                  "$ref": "#/components/schemas/JIS"
                },
                "timestamp": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OperatorProfile": {
        "type": "object",
        "description": "Aggregate judgment profile computed across the operator's full history.",
        "properties": {
          "interactions_scored": {
            "type": "integer",
            "minimum": 0
          },
          "mean_jis": {
            "$ref": "#/components/schemas/JIS"
          },
          "current_jis": {
            "$ref": "#/components/schemas/JIS"
          },
          "trend": {
            "$ref": "#/components/schemas/Trend"
          },
          "classification": {
            "$ref": "#/components/schemas/JISBand"
          },
          "dimension_means": {
            "$ref": "#/components/schemas/DimensionScores"
          },
          "dimension_weakness": {
            "type": "array",
            "description": "Ordered list of dimensions below 60, weakest first.",
            "items": {
              "$ref": "#/components/schemas/Dimension"
            }
          },
          "decay": {
            "$ref": "#/components/schemas/DecayProjection"
          }
        }
      },
      "OrgDashboardResponse": {
        "type": "object",
        "required": [
          "organization",
          "domain",
          "tier",
          "dashboard",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "organization": {
            "type": "string"
          },
          "domain": {
            "$ref": "#/components/schemas/Domain"
          },
          "tier": {
            "type": "string",
            "enum": [
              "L1",
              "L2",
              "L3"
            ],
            "description": "COHESION certification tier. L1 Monitoring, L2 Maintenance, L3 Certified."
          },
          "dashboard": {
            "$ref": "#/components/schemas/OrgDashboard"
          },
          "org_compliance": {
            "$ref": "#/components/schemas/OrgComplianceAssessment"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OrgComplianceAssessment": {
        "type": "object",
        "description": "Cycle 3.5 cascade #3: spec §5.1 org-level compliance determination.\nAn organisation MUST NOT claim Article 14 compliance if EITHER\nmore than 10% of operators in high-risk oversight roles have\nJIS<60, OR any operator in a critical-decision role has JIS<40.\n",
        "required": [
          "compliant",
          "reason",
          "total",
          "failing_operator_count"
        ],
        "properties": {
          "compliant": {
            "type": "boolean",
            "description": "True if neither §5.1 condition is violated."
          },
          "reason": {
            "type": "string",
            "description": "Human-readable explanation of the determination."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total operators considered."
          },
          "failing_operator_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Union (not sum) of operators violating either condition."
          },
          "condition_a_violations": {
            "type": "integer",
            "minimum": 0,
            "description": "Count of operators with JIS<60 (>10% triggers non-compliance)."
          },
          "condition_b_violations": {
            "type": "integer",
            "minimum": 0,
            "description": "Count of operators with JIS<40 (any triggers non-compliance)."
          },
          "conditions": {
            "type": "object",
            "description": "The threshold definitions used for the determination.",
            "properties": {
              "a": {
                "type": "object",
                "properties": {
                  "threshold": {
                    "type": "number",
                    "format": "float"
                  },
                  "gate": {
                    "type": "string"
                  }
                }
              },
              "b": {
                "type": "object",
                "properties": {
                  "threshold": {
                    "type": "number",
                    "format": "float"
                  },
                  "gate": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "OrgDashboard": {
        "type": "object",
        "description": "Aggregated organization view.",
        "properties": {
          "operator_count": {
            "type": "integer",
            "minimum": 0
          },
          "mean_org_jis": {
            "$ref": "#/components/schemas/JIS"
          },
          "distribution": {
            "type": "object",
            "properties": {
              "exemplary": {
                "type": "integer",
                "minimum": 0
              },
              "proficient": {
                "type": "integer",
                "minimum": 0
              },
              "adequate": {
                "type": "integer",
                "minimum": 0
              },
              "at_risk": {
                "type": "integer",
                "minimum": 0
              },
              "impaired": {
                "type": "integer",
                "minimum": 0
              },
              "non_functional": {
                "type": "integer",
                "minimum": 0
              }
            }
          },
          "org_compliance_status": {
            "$ref": "#/components/schemas/OrgComplianceStatus"
          },
          "weakest_dimensions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Dimension"
            }
          },
          "operators_below_60_pct": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "operators_below_40_count": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "MaintenanceRequest": {
        "type": "object",
        "required": [
          "operator_id"
        ],
        "description": "Body for `POST /v1/maintenance/recommend`. The `api_key` field is\ndeprecated and optional; prefer the `X-API-Key` header.\n",
        "properties": {
          "api_key": {
            "type": "string",
            "maxLength": 256,
            "deprecated": true,
            "x-deprecated-as-of": "2026-04-17",
            "x-sunset-date": "2026-07-15",
            "description": "**DEPRECATED 2026-04-17, sunset 2026-07-15.** Use the `X-API-Key` header.\n"
          },
          "operator_id": {
            "type": "string",
            "maxLength": 256,
            "pattern": "^[a-zA-Z0-9_-]{1,256}$"
          }
        }
      },
      "MaintenanceResponse": {
        "type": "object",
        "required": [
          "recommendation",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "recommendation": {
            "$ref": "#/components/schemas/MaintenanceRecommendation"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MaintenanceRecommendation": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MaintenanceDecision"
          },
          {
            "type": "object",
            "properties": {
              "operator_id": {
                "type": "string"
              },
              "current_jis": {
                "$ref": "#/components/schemas/JIS"
              },
              "trend": {
                "$ref": "#/components/schemas/Trend"
              },
              "domain": {
                "$ref": "#/components/schemas/Domain"
              },
              "compliance": {
                "$ref": "#/components/schemas/ComplianceEvaluation"
              },
              "decay_projection": {
                "$ref": "#/components/schemas/DecayProjection"
              },
              "exercises": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MaintenanceExercise"
                }
              }
            }
          }
        ]
      },
      "MaintenanceExercise": {
        "type": "object",
        "required": [
          "type",
          "description"
        ],
        "properties": {
          "type": {
            "type": "string",
            "example": "supervised_session"
          },
          "duration_minutes": {
            "type": "integer",
            "minimum": 1
          },
          "count": {
            "type": "integer",
            "minimum": 1
          },
          "frequency": {
            "type": "string",
            "enum": [
              "daily",
              "3x_weekly",
              "2x_weekly",
              "weekly"
            ]
          },
          "description": {
            "type": "string"
          }
        }
      },
      "MaintenanceDecision": {
        "type": "object",
        "description": "Decision record for whether and how to trigger an adaptive-calibration\nintervention on the operator's next eligible interaction.\n",
        "properties": {
          "trigger_intervention": {
            "type": "boolean"
          },
          "intervention_type": {
            "type": "string",
            "description": "The class of adaptive intervention recommended. `none` when no\nintervention is warranted.\n",
            "enum": [
              "none",
              "awareness_prompt",
              "targeted_exercise_set",
              "structured_recalibration",
              "single_dimension_boost",
              "targeted_dimension_recovery",
              "trend_arrest_exercises",
              "immediate_supervised_practice"
            ]
          },
          "urgency": {
            "type": "string",
            "enum": [
              "none",
              "low",
              "moderate",
              "high",
              "critical"
            ]
          },
          "rationale": {
            "type": "string",
            "description": "Short machine-readable explanation. Not shown to operators."
          }
        }
      },
      "ComplianceReportResponse": {
        "type": "object",
        "required": [
          "report",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "report": {
            "$ref": "#/components/schemas/ComplianceReport"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ComplianceReport": {
        "type": "object",
        "description": "Persisted Article 14 compliance report snapshot.\n\nCycle 3.5 cascade #1 + #2 added the `score_source` attribution\n(spec §4.4: cited values are EWMA-smoothed) and the\n`provisional_excluded_count` + `provisional_excluded_note`\nmetadata (spec §4.3: provisional operators MUST be excluded\nfrom the report aggregation).\n",
        "required": [
          "report_id",
          "generated_at",
          "overall_status"
        ],
        "properties": {
          "report_id": {
            "type": "string"
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "organization": {
            "type": "string"
          },
          "domain": {
            "$ref": "#/components/schemas/Domain"
          },
          "overall_status": {
            "type": "string",
            "enum": [
              "compliant",
              "at_risk",
              "non_compliant"
            ]
          },
          "operators_summary": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer",
                "minimum": 0
              },
              "below_60_count": {
                "type": "integer",
                "minimum": 0
              },
              "below_60_pct": {
                "type": "number",
                "format": "float",
                "minimum": 0,
                "maximum": 100
              },
              "below_40_count": {
                "type": "integer",
                "minimum": 0
              }
            }
          },
          "dimensions_below_threshold": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Dimension"
            }
          },
          "dashboard_ref": {
            "$ref": "#/components/schemas/OrgDashboard"
          },
          "regulatory_framework": {
            "type": "string",
            "default": "EU AI Act Article 14 (high-risk AI, human oversight)"
          },
          "score_source": {
            "type": "string",
            "enum": [
              "displayed_jis",
              "computed_jis"
            ],
            "description": "Spec §4.4: which value the report cites. Defaults to\n`displayed_jis` (the 30-day-half-life EWMA), the normative\nvalue for compliance reporting.\n"
          },
          "score_source_note": {
            "type": "string",
            "description": "Human-readable explanation of the score_source choice with\nspec citation, for audit/regulator review.\n"
          },
          "provisional_excluded_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Spec §4.3: count of operators excluded from this report's\naggregation because their data did not yet meet the\n50-interactions / 10-days gate.\n"
          },
          "provisional_excluded_note": {
            "type": "string",
            "description": "Human-readable explanation of the provisional-exclusion gate\nand the operator count excluded, for audit trail.\n"
          }
        }
      },
      "JIS": {
        "type": "number",
        "format": "float",
        "minimum": 0,
        "maximum": 100,
        "description": "Judgment Independence Score. 0 = cannot provide Article 14 oversight,\n100 = exemplary independent judgment.\n"
      },
      "JISBand": {
        "type": "string",
        "enum": [
          "exemplary",
          "proficient",
          "adequate",
          "at_risk",
          "impaired",
          "non_functional"
        ]
      },
      "Trend": {
        "type": "string",
        "enum": [
          "improving",
          "stable",
          "declining"
        ],
        "description": "EWMA-based trend classification over the operator's recent history."
      },
      "DimensionScores": {
        "type": "object",
        "description": "Score in [0, 100] for each of the seven dimensions.",
        "required": [
          "deferral_resistance",
          "error_detection_capability",
          "independent_performance",
          "deliberation_depth",
          "post_error_recalibration",
          "domain_confidence",
          "decision_autonomy"
        ],
        "properties": {
          "deferral_resistance": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "error_detection_capability": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "independent_performance": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "deliberation_depth": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "post_error_recalibration": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "domain_confidence": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "decision_autonomy": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          }
        }
      },
      "DecayProjection": {
        "type": "object",
        "description": "Projected Judgment Decay curve for the operator's domain per spec §6.\nDecay formula: `JIS(t) = JIS_0 · (1 − α · ln(1 + β · t))`, floored at\nper-domain `floor`. `projected_jis` assumes no maintenance\nintervention; `mitigated_projected_jis` assumes the recommended\nmaintenance is applied at efficacy γ.\n\nCycle 3 fix #5 (2026-04-25) added `decay_rate` (back-compat alias for\nα, the spec §6 primary rate parameter) and `decay_acceleration` (β,\nthe second decay parameter).\n",
        "properties": {
          "domain": {
            "$ref": "#/components/schemas/Domain"
          },
          "alpha": {
            "type": "number",
            "format": "float"
          },
          "beta": {
            "type": "number",
            "format": "float"
          },
          "decay_rate": {
            "type": "number",
            "format": "float",
            "description": "Back-compat alias: spec §6 primary rate parameter α. Equivalent\nto the `alpha` field. Pre-Cycle-3 (2026-04-25) this was a\ndifferent code-invented `lambda` value; new clients should\nconsume `alpha` directly.\n"
          },
          "decay_acceleration": {
            "type": "number",
            "format": "float",
            "description": "Spec §6 second decay parameter β. Equivalent to the `beta` field.\n"
          },
          "recovery_rate": {
            "oneOf": [
              {
                "type": "number",
                "format": "float"
              },
              {
                "type": "null"
              }
            ],
            "description": "Back-compat field. Pre-Cycle-3 this was a code-invented\nrecovery_rate; spec §6 has no such concept. Always `null`\nin v1.0+. Will be removed in v2.0.\n"
          },
          "floor": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "current_trend": {
            "$ref": "#/components/schemas/Trend"
          },
          "days_to_non_compliance": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ]
          },
          "projections": {
            "type": "array",
            "description": "Per-day projection table at 7, 14, 30, 60, 90 day horizons.",
            "items": {
              "type": "object",
              "properties": {
                "days": {
                  "type": "integer",
                  "minimum": 0
                },
                "projected_jis": {
                  "type": "number",
                  "format": "float",
                  "minimum": 0,
                  "maximum": 100
                },
                "compliance_status": {
                  "type": "string",
                  "enum": [
                    "compliant",
                    "at_risk",
                    "non_compliant"
                  ]
                }
              }
            }
          },
          "projected_jis_30d": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "projected_jis_90d": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          },
          "mitigated_projected_jis_90d": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 100
          }
        }
      },
      "ComplianceEvaluation": {
        "type": "object",
        "required": [
          "article_14_status"
        ],
        "properties": {
          "article_14_status": {
            "type": "string",
            "enum": [
              "compliant",
              "at_risk",
              "non_compliant"
            ]
          },
          "band": {
            "$ref": "#/components/schemas/JISBand"
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "OrgComplianceStatus": {
        "type": "string",
        "enum": [
          "compliant",
          "at_risk",
          "non_compliant"
        ],
        "description": "Organization-level aggregate. `non_compliant` if >10% of operators have\nJIS < 60 or any operator in a critical-decision role has JIS < 40.\n"
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "status",
          "service",
          "version"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok"
            ],
            "example": "ok"
          },
          "service": {
            "type": "string",
            "example": "COHESION Judgment Independence Score API"
          },
          "version": {
            "type": "string",
            "example": "1.0.0"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "APIInfoResponse": {
        "type": "object",
        "required": [
          "service",
          "version",
          "endpoints"
        ],
        "properties": {
          "service": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "endpoints": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "compliance": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "EU AI Act Article 14",
              "NIST AI RMF",
              "ISO/IEC 42001"
            ]
          },
          "patent": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "example": "pending"
              },
              "filed": {
                "type": "string",
                "format": "date",
                "example": "2026-04-13"
              },
              "confirmation": {
                "type": "string",
                "example": "1414"
              },
              "claims": {
                "type": "integer",
                "example": 31
              }
            }
          }
        }
      },
      "AdminKeyRotateResponse": {
        "type": "object",
        "description": "Returned exactly once on successful rotation. The `new_api_key` value\nis the only opportunity to capture the plaintext key; subsequent\nrequests return only the prefix.\n",
        "required": [
          "new_api_key",
          "prefix",
          "rotated_at",
          "warning",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "new_api_key": {
            "type": "string",
            "description": "Plaintext key, format `ck_live_<26-char-Crockford-base32>`.",
            "pattern": "^ck_live_[0-9A-HJKMNP-TV-Z]{26}$"
          },
          "prefix": {
            "type": "string",
            "description": "8-character non-secret prefix indexed in `organizations.api_key_prefix`.",
            "example": "ck_live_"
          },
          "rotated_at": {
            "type": "string",
            "format": "date-time"
          },
          "warning": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AdminKeyRevokeResponse": {
        "type": "object",
        "required": [
          "revoked",
          "org_id",
          "revoked_at",
          "note",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "revoked": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "org_id": {
            "type": "string"
          },
          "revoked_at": {
            "type": "string",
            "format": "date-time"
          },
          "note": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AuditEventType": {
        "type": "string",
        "description": "Whitelisted audit event type. Unknown values are rejected with\n`422 VALIDATION_FAILED`. Server-enforced in `worker.js`.\n",
        "enum": [
          "AUTH_SUCCESS",
          "AUTH_FAIL_UNKNOWN_PREFIX",
          "AUTH_FAIL_WRONG_HASH",
          "AUTH_FAIL_INACTIVE",
          "AUTH_FAIL_EXPIRED",
          "AUTH_FAIL_RATE_LIMITED_IP",
          "AUTH_FAIL_RATE_LIMITED_KEY",
          "AUTH_DEPRECATED_BODY_KEY",
          "KEY_ROTATED",
          "KEY_REVOKED",
          "KEY_EMERGENCY_REVOKED",
          "KEY_EXPIRED",
          "CRON_RUN"
        ]
      },
      "AuditLogEvent": {
        "type": "object",
        "description": "One row from `audit_log`, scoped to the caller's organization.",
        "required": [
          "id",
          "timestamp",
          "event_type",
          "path",
          "method",
          "status",
          "request_id"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "event_type": {
            "$ref": "#/components/schemas/AuditEventType"
          },
          "api_key_prefix": {
            "type": [
              "string",
              "null"
            ]
          },
          "path": {
            "type": "string"
          },
          "method": {
            "type": "string",
            "enum": [
              "GET",
              "POST",
              "HEAD",
              "OPTIONS"
            ]
          },
          "status": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599
          },
          "request_id": {
            "type": "string"
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AdminAuditLogResponse": {
        "type": "object",
        "required": [
          "events",
          "count",
          "filters",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditLogEvent"
            }
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 500,
            "description": "Number of events returned (never exceeds `limit`)."
          },
          "filters": {
            "type": "object",
            "required": [
              "event_type",
              "since",
              "until",
              "limit"
            ],
            "properties": {
              "event_type": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "since": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "until": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 500
              }
            }
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AssessmentSubmitRequest": {
        "type": "object",
        "required": [
          "sessionId",
          "createdAt",
          "records",
          "score"
        ],
        "description": "Public demo submission body. `records` is an array of up to 100\nper-scenario decision records as captured by the `/demo/` UI; schema\nis intentionally loose here so the UI can evolve without an API\nversion bump. Only `score.jis` is strictly validated.\n",
        "properties": {
          "sessionId": {
            "type": "string",
            "maxLength": 128,
            "pattern": "^[a-zA-Z0-9_-]{1,128}$",
            "description": "Client-generated demo session identifier."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "maxLength": 64
          },
          "userAgent": {
            "type": "string",
            "maxLength": 120,
            "description": "Truncated User-Agent string for analytics. Optional."
          },
          "domain": {
            "type": "string",
            "maxLength": 32,
            "description": "Domain the demo run targeted (e.g. `healthcare`, `aviation`)."
          },
          "score": {
            "type": "object",
            "required": [
              "jis"
            ],
            "properties": {
              "jis": {
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              "dimensions": {
                "$ref": "#/components/schemas/DimensionScores"
              },
              "domain": {
                "type": "string"
              }
            }
          },
          "records": {
            "type": "array",
            "maxItems": 100,
            "description": "Per-scenario records from the demo UI. Opaque to the server except\nfor length.\n",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "AssessmentSubmitResponse": {
        "type": "object",
        "required": [
          "ok",
          "sessionId",
          "shareUrl",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "sessionId": {
            "type": "string"
          },
          "shareUrl": {
            "type": "string",
            "format": "uri"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AssessmentGetResponse": {
        "type": "object",
        "required": [
          "sessionId",
          "createdAt",
          "jis",
          "request_id",
          "timestamp"
        ],
        "properties": {
          "sessionId": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "domain": {
            "type": "string"
          },
          "jis": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "dimensions": {
            "$ref": "#/components/schemas/DimensionScores"
          },
          "records": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time"
          },
          "request_id": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ErrorCode": {
        "type": "string",
        "description": "Stable, machine-readable error code. Clients SHOULD branch on this\nrather than the human `message` (which is subject to wording / i18n\nchanges). The 9 values cover every 4xx / 5xx response the API emits.\n\n* `UNAUTHORIZED`: API key missing, invalid, inactive, expired, or the\n  request bypassed the Cloudflare edge (returned for 401).\n* `RBAC_DENIED`: Authentication succeeded but the caller's role lacks\n  the scope required by the endpoint per the 2026-05-06 DRS RBAC\n  matrix (returned for 403 on `/v1/decision/score`,\n  `/v1/decision/review`, and other RBAC-gated routes).\n* `RATE_LIMITED`: IP-level (layer 1) or per-key (layer 2) budget\n  exhausted. Always paired with a `Retry-After` header.\n* `VALIDATION_FAILED`: One or more fields failed schema validation.\n  The `details` array carries per-field messages.\n* `REQUEST_TOO_LARGE`: Request body exceeded the documented cap\n  (1 MB single, 5 MB batch).\n* `INVALID_JSON`: Body could not be parsed as UTF-8 JSON.\n* `NOT_FOUND`: Route or resource (operator, etc.) does not exist\n  for this organization.\n* `METHOD_NOT_ALLOWED`: Reserved; not currently emitted.\n* `INTERNAL_ERROR`: Unhandled server error. Retry with exponential\n  backoff.\n",
        "enum": [
          "UNAUTHORIZED",
          "RATE_LIMITED",
          "VALIDATION_FAILED",
          "REQUEST_TOO_LARGE",
          "INVALID_JSON",
          "NOT_FOUND",
          "METHOD_NOT_ALLOWED",
          "INTERNAL_ERROR",
          "RBAC_DENIED"
        ]
      },
      "ErrorEnvelope": {
        "type": "object",
        "description": "Stripe-style nested error body. The HTTP status code is authoritative;\nit is **never** echoed inside the JSON body (so distinct failure modes\nlook identical to a body-only consumer (K8 enumeration resistance).\n",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "request_id",
              "timestamp"
            ],
            "properties": {
              "code": {
                "$ref": "#/components/schemas/ErrorCode"
              },
              "message": {
                "type": "string",
                "description": "Human-readable explainer. Free-form, may be reworded between\nreleases. Do not pattern-match on this field; use `code` instead.\n"
              },
              "request_id": {
                "type": "string",
                "description": "Mirrors the `X-Request-ID` response header."
              },
              "timestamp": {
                "type": "string",
                "format": "date-time",
                "description": "ISO-8601 UTC timestamp the error was emitted."
              },
              "details": {
                "type": "array",
                "description": "Present on `VALIDATION_FAILED`. One human-readable message\nper failed field/constraint.\n",
                "items": {
                  "type": "string"
                }
              },
              "index": {
                "type": "integer",
                "description": "Present on batch-validation failures. Zero-based index of the\nfirst interaction whose payload failed validation.\n",
                "minimum": 0
              }
            }
          }
        }
      },
      "Error": {
        "$ref": "#/components/schemas/ErrorEnvelope"
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "API key missing, invalid, expired, or scoped to an inactive organization.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "error": {
                "code": "UNAUTHORIZED",
                "message": "UNAUTHORIZED",
                "request_id": "7c2bd4de00a1b921",
                "timestamp": "2026-04-16T14:52:33.211Z"
              }
            }
          }
        }
      },
      "UnauthorizedBodyAuth": {
        "description": "Same as `Unauthorized` but additionally carries the deprecation\nheaders because the request used the deprecated `api_key` body field.\n",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          },
          "Deprecation": {
            "$ref": "#/components/headers/Deprecation"
          },
          "Sunset": {
            "$ref": "#/components/headers/Sunset"
          },
          "Link": {
            "$ref": "#/components/headers/LinkDeprecation"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "error": {
                "code": "UNAUTHORIZED",
                "message": "UNAUTHORIZED",
                "request_id": "7c2bd4de00a1b921",
                "timestamp": "2026-04-16T14:52:33.211Z"
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Authentication succeeded but the caller's role lacks the required\nscope for this endpoint. RBAC scope enforced per\nscoring-api/CLAUDE.md spec §4.5 / Appendix B.\n",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "error": {
                "code": "RBAC_DENIED",
                "message": "Caller role lacks the required scope for this endpoint.",
                "request_id": "7c2bd4de00a1b921",
                "timestamp": "2026-04-16T14:52:33.211Z"
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested resource does not exist for this organization.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "error": {
                "code": "NOT_FOUND",
                "message": "Operator not found",
                "request_id": "7c2bd4de00a1b921",
                "timestamp": "2026-04-16T14:52:33.211Z"
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "Request body exceeds the documented size limit.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "error": {
                "code": "REQUEST_TOO_LARGE",
                "message": "Request body too large (max 1048576 bytes)",
                "request_id": "7c2bd4de00a1b921",
                "timestamp": "2026-04-16T14:52:33.211Z"
              }
            }
          }
        }
      },
      "ValidationFailed": {
        "description": "One or more fields failed schema validation.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "error": {
                "code": "VALIDATION_FAILED",
                "message": "Validation failed",
                "request_id": "7c2bd4de00a1b921",
                "timestamp": "2026-04-16T14:52:33.211Z",
                "details": [
                  "interaction.decision must be one of: accepted, modified, rejected, independent",
                  "interaction.scroll_depth must be a number between 0.0 and 1.0"
                ]
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Request budget exhausted. Layer 1 (per-IP, 60 req/60s, pre-auth) or\nlayer 2 (per-key, 1000 req/60s, post-auth) tripped; both surface\nthe same envelope and `Retry-After` header.\n",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "error": {
                "code": "RATE_LIMITED",
                "message": "Rate limit exceeded. Maximum 1000 requests per minute.",
                "request_id": "7c2bd4de00a1b921",
                "timestamp": "2026-04-16T14:52:33.211Z"
              }
            }
          }
        }
      },
      "InvalidJSON": {
        "description": "Request body could not be parsed as UTF-8 JSON.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "error": {
                "code": "INVALID_JSON",
                "message": "Invalid JSON body",
                "request_id": "7c2bd4de00a1b921",
                "timestamp": "2026-04-16T14:52:33.211Z"
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "Server error. Retry with exponential backoff.",
        "headers": {
          "X-Request-ID": {
            "$ref": "#/components/headers/XRequestID"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      }
    }
  }
}