{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://github.com/andrewhuot/headless-chat-sdk/schemas/transport.schema.json",
  "title": "TransportContract",
  "description": "Public transport and recovery contract. Mirrors packages/gecx-chat/src/transport/ChatTransport.ts and packages/gecx-chat/src/transport/recoveryPolicy.ts. See docs/internal/transport-and-recovery-contract.md.",
  "definitions": {
    "TransportClass": {
      "type": "string",
      "enum": ["request-response", "server-stream", "bidi"],
      "description": "Tier-0 (HTTP request-response), tier-1 (server-stream over HTTP), or tier-2 (long-lived duplex)."
    },
    "TransportCapabilities": {
      "type": "object",
      "required": ["class", "reconnect", "resume", "multiplex", "protocolVersion"],
      "additionalProperties": false,
      "properties": {
        "class": { "$ref": "#/definitions/TransportClass" },
        "reconnect": { "type": "boolean", "description": "True if the transport implements reconnect()." },
        "resume": { "type": "boolean", "description": "True if the transport implements resumeStream(cursor)." },
        "multiplex": { "type": "boolean", "description": "True if the transport can share a connection across sessions." },
        "protocolVersion": { "type": "string", "description": "Wire-protocol version string." },
        "attachments": { "$ref": "#/definitions/AttachmentAdapterCapabilities" }
      }
    },
    "AttachmentLifecycleStatus": {
      "type": "string",
      "enum": ["selected", "validating", "rejected", "queued", "uploading", "uploaded", "scan_pending", "scan_failed", "ready_to_send", "sent", "failed", "removed"]
    },
    "AttachmentScanStatus": {
      "type": "string",
      "enum": ["not_required", "pending", "passed", "failed"]
    },
    "AttachmentAdapterCapabilities": {
      "type": "object",
      "required": ["kind", "supportsProgress", "supportsCancel", "supportsRemove", "supportsRetry", "supportsScanStatus"],
      "additionalProperties": false,
      "properties": {
        "kind": {
          "type": "string",
          "enum": ["inline-blob", "proxy-upload", "presigned-url", "unsupported"]
        },
        "supportsProgress": { "type": "boolean" },
        "supportsCancel": { "type": "boolean" },
        "supportsRemove": { "type": "boolean" },
        "supportsRetry": { "type": "boolean" },
        "supportsScanStatus": { "type": "boolean" },
        "maxBytes": { "type": "integer", "minimum": 0 },
        "maxFileCount": { "type": "integer", "minimum": 0 },
        "allowedMimeTypes": { "type": "array", "items": { "type": "string" } },
        "remediation": { "type": "string" }
      }
    },
    "UploadProgressEvent": {
      "type": "object",
      "required": ["progress"],
      "additionalProperties": false,
      "properties": {
        "attachmentId": { "type": "string" },
        "progress": { "type": "number", "minimum": 0, "maximum": 100 },
        "url": { "type": "string", "format": "uri" },
        "status": { "type": "string", "enum": ["queued", "uploading", "uploaded", "completed", "scan_pending", "scan_failed", "ready_to_send", "failed"] },
        "lifecycle": { "$ref": "#/definitions/AttachmentLifecycleStatus" },
        "error": { "type": "string" },
        "errorCode": { "type": "string" },
        "remediation": { "type": "string" },
        "scanStatus": { "$ref": "#/definitions/AttachmentScanStatus" },
        "metadata": { "type": "object" }
      }
    },
    "TurnCursor": {
      "type": "object",
      "required": ["sessionId", "responseId", "idempotencyKey", "lastSequence", "startedAt"],
      "additionalProperties": false,
      "properties": {
        "sessionId": { "type": "string" },
        "responseId": { "type": "string" },
        "idempotencyKey": { "type": "string", "description": "Survives reconnect for the lifetime of the turn." },
        "lastSequence": { "type": "integer", "minimum": -1 },
        "startedAt": { "type": "string", "format": "date-time" }
      }
    },
    "RecoveryPolicy": {
      "type": "object",
      "required": ["maxAttempts", "initialBackoffMs", "maxBackoffMs", "jitter", "resumeMode"],
      "additionalProperties": false,
      "properties": {
        "maxAttempts": { "type": "integer", "minimum": 1 },
        "initialBackoffMs": { "type": "integer", "minimum": 0 },
        "maxBackoffMs": { "type": "integer", "minimum": 0 },
        "jitter": { "type": "string", "enum": ["none", "equal", "full"] },
        "resumeMode": { "type": "string", "enum": ["replay", "resume", "none"] }
      }
    },
    "AbortReason": {
      "type": "string",
      "enum": ["user", "page_unload", "replaced", "offline", "recovery_exhausted", "shutdown"]
    },
    "NetworkMode": {
      "type": "string",
      "enum": ["auto", "strict", "off"]
    },
    "MultiTabMode": {
      "type": "string",
      "enum": ["leader", "broadcast", "off"]
    },
    "OutboxEntry": {
      "type": "object",
      "required": ["idempotencyKey", "queuedAt"],
      "additionalProperties": true,
      "properties": {
        "idempotencyKey": { "type": "string" },
        "queuedAt": { "type": "string", "format": "date-time" }
      }
    }
  },
  "type": "object",
  "properties": {
    "transportClass": { "$ref": "#/definitions/TransportClass" },
    "capabilities": { "$ref": "#/definitions/TransportCapabilities" },
    "cursor": { "$ref": "#/definitions/TurnCursor" },
    "policy": { "$ref": "#/definitions/RecoveryPolicy" }
  }
}
