{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://docs.testcabinet.ai/schema/backend-api/publish-run-request.schema.json",
  "title": "PublishRunRequest",
  "description": "The body of POST /runs: a published run's machine-generated record, its hand-written review, and the resolved public links. The operator's component has already released the source repo and deployed the build before calling, so it sends the captured URLs. Idempotent on record.id.",
  "type": "object",
  "additionalProperties": false,
  "required": ["record", "review", "links"],
  "properties": {
    "record": {
      "$ref": "https://docs.testcabinet.ai/schema/core/run-record.schema.json",
      "description": "A full RunRecord. Its `links` MAY be empty here; the `links` below are authoritative and the backend writes them onto the stored record."
    },
    "review": {
      "$ref": "https://docs.testcabinet.ai/schema/backend-api/review.schema.json"
    },
    "links": { "$ref": "#/$defs/RunLinks" }
  },
  "$defs": {
    "RunLinks": {
      "type": "object",
      "additionalProperties": false,
      "description": "The resolved public links for a run. These are the authoritative copies the backend writes onto the stored record.",
      "properties": {
        "sourceRepo": {
          "type": ["string", "null"],
          "description": "The public repository holding the run's generated source."
        },
        "playableBuild": {
          "type": ["string", "null"],
          "description": "The deployment URL the build tool reported, recorded verbatim — NOT a host constructed from the run id and project, which Cloudflare's branch-alias sanitization may truncate."
        }
      }
    }
  }
}
