{
  "openapi": "3.1.0",
  "info": {
    "title": "Workbench Tower Defence public read API",
    "version": "1.0.0",
    "description": "Read-only discovery for published rules, Ranked Challenge briefs, leaderboard records, canonical public runs, sanitized replays, build guides, share images, feeds, and sitemaps. Mutation endpoints are deliberately omitted."
  },
  "servers": [{ "url": "https://workbench-tower-defence.pages.dev" }],
  "tags": [
    { "name": "Catalog", "description": "Published rules and Ranked Challenge discovery." },
    { "name": "Leaderboard", "description": "Accepted public run summaries." },
    { "name": "Runs", "description": "Canonical, privacy-filtered public run documents and replay resources." },
    { "name": "Discovery", "description": "Feeds, oEmbed, and sitemap resources." }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "tags": ["Catalog"],
        "summary": "Read public-stack health",
        "responses": { "200": { "description": "Current public service status" }, "503": { "description": "A required public-stack component is unavailable" } }
      }
    },
    "/api/rules-versions": {
      "get": {
        "tags": ["Catalog"],
        "summary": "List published rules versions",
        "responses": { "200": { "description": "Published rules catalog" } }
      }
    },
    "/api/challenges": {
      "get": {
        "tags": ["Catalog"],
        "summary": "List current Ranked Challenge briefs",
        "responses": { "200": { "description": "Public challenge briefs; no ticket, nonce, or signature data" } }
      }
    },
    "/api/records": {
      "get": {
        "tags": ["Leaderboard"],
        "summary": "List public Leaderboard records",
        "parameters": [
          { "name": "difficulty", "in": "query", "schema": { "type": "string", "enum": ["apprentice", "journeyman", "master", "grandmaster", "legendary", "impossible"] } },
          { "name": "category", "in": "query", "schema": { "type": "string" } },
          { "name": "mode", "in": "query", "schema": { "type": "string", "enum": ["solo", "finder", "runbook", "fork", "challenge"] } },
          { "name": "gameVersion", "in": "query", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100 } }
        ],
        "responses": { "200": { "description": "Privacy-filtered public record summaries" } }
      }
    },
    "/api/records/{id}": {
      "get": {
        "tags": ["Leaderboard"],
        "summary": "Read one legacy public record projection",
        "parameters": [{ "$ref": "#/components/parameters/RunId" }],
        "responses": { "200": { "description": "Privacy-filtered public record detail" }, "404": { "description": "Record not found" }, "410": { "description": "Public replay evidence is no longer available" } }
      }
    },
    "/runs/{id}": {
      "get": {
        "tags": ["Runs"],
        "summary": "Open the canonical public result and replay page",
        "parameters": [{ "$ref": "#/components/parameters/RunId" }],
        "responses": { "200": { "description": "Server-rendered public run document" }, "404": { "description": "Run not found" }, "410": { "description": "Run removed or exact replay evidence unavailable" }, "503": { "description": "Public replay service temporarily unavailable" } }
      },
      "head": {
        "tags": ["Runs"],
        "summary": "Read canonical public-run headers",
        "parameters": [{ "$ref": "#/components/parameters/RunId" }],
        "responses": { "200": { "description": "Run exists" }, "404": { "description": "Run not found" }, "410": { "description": "Run no longer available" } }
      }
    },
    "/runs/{id}.json": {
      "get": {
        "tags": ["Runs"],
        "summary": "Read a sanitized machine-readable public run",
        "parameters": [{ "$ref": "#/components/parameters/RunId" }],
        "responses": { "200": { "description": "Public run facts with no private competitive fields" }, "404": { "description": "Run not found" }, "410": { "description": "Run no longer available" }, "503": { "description": "Public replay service temporarily unavailable" } }
      },
      "head": {
        "tags": ["Runs"],
        "summary": "Read sanitized public-run JSON headers",
        "parameters": [{ "$ref": "#/components/parameters/RunId" }],
        "responses": { "200": { "description": "Public run exists" }, "404": { "description": "Run not found" }, "410": { "description": "Run no longer available" }, "503": { "description": "Public replay service temporarily unavailable" } }
      }
    },
    "/runs/{id}/replay": {
      "get": {
        "tags": ["Runs"],
        "summary": "Read the sanitized portable replay",
        "parameters": [
          { "$ref": "#/components/parameters/RunId" },
          { "name": "download", "in": "query", "description": "Use 1 or true to request attachment disposition.", "schema": { "type": "string", "enum": ["1", "true"] } }
        ],
        "responses": { "200": { "description": "Sanitized replay JSON" }, "404": { "description": "Run not found" }, "410": { "description": "Replay no longer available" }, "503": { "description": "Replay temporarily unavailable" } }
      },
      "head": {
        "tags": ["Runs"],
        "summary": "Read sanitized replay headers",
        "parameters": [{ "$ref": "#/components/parameters/RunId" }],
        "responses": { "200": { "description": "Replay exists" }, "404": { "description": "Run not found" }, "410": { "description": "Replay no longer available" }, "503": { "description": "Replay temporarily unavailable" } }
      }
    },
    "/runs/{id}/guide": {
      "get": {
        "tags": ["Runs"],
        "summary": "Open the semantic Standard build guide derived from a public replay",
        "parameters": [{ "$ref": "#/components/parameters/RunId" }],
        "responses": { "200": { "description": "Server-rendered build guide" }, "404": { "description": "Run not found" }, "410": { "description": "Replay no longer available" }, "503": { "description": "Guide temporarily unavailable" } }
      },
      "head": {
        "tags": ["Runs"],
        "summary": "Read public build-guide headers",
        "parameters": [{ "$ref": "#/components/parameters/RunId" }],
        "responses": { "200": { "description": "Guide exists" }, "404": { "description": "Run not found" }, "410": { "description": "Replay no longer available" }, "503": { "description": "Guide temporarily unavailable" } }
      }
    },
    "/media/runs/{card}": {
      "get": {
        "tags": ["Runs"],
        "summary": "Read an immutable public-run social image",
        "description": "The card name contains the run ID, presentation hash, optional format, and .png extension. Formats are landscape, square, portrait, story, and pinterest.",
        "parameters": [{ "name": "card", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^r_[a-f0-9]{16,32}-[a-f0-9]{16}(?:-(?:landscape|square|portrait|story|pinterest))?\\.png$" } }],
        "responses": { "200": { "description": "PNG share image" }, "206": { "description": "Single byte range" }, "302": { "description": "Redirect to the current presentation revision" }, "404": { "description": "Card or run not found" }, "410": { "description": "Run no longer available" }, "416": { "description": "Requested byte range is invalid" } }
      },
      "head": {
        "tags": ["Runs"],
        "summary": "Read public-run social-image headers",
        "parameters": [{ "name": "card", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Image exists" }, "302": { "description": "Redirect to current presentation revision" }, "404": { "description": "Card or run not found" } }
      }
    },
    "/oembed": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Read safe link-only oEmbed metadata for a canonical public run",
        "parameters": [
          { "name": "url", "in": "query", "required": true, "schema": { "type": "string", "format": "uri" } },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["json"] } }
        ],
        "responses": { "200": { "description": "oEmbed 1.0 link result with public thumbnail" }, "400": { "description": "A canonical run URL was not supplied" }, "404": { "description": "Run not found" }, "410": { "description": "Run no longer available" }, "503": { "description": "Public replay service temporarily unavailable" } }
      }
    },
    "/play/standard/{difficulty}": {
      "get": {
        "tags": ["Catalog"],
        "summary": "Open a clean Standard game action",
        "description": "A noindex action URL that redirects to the interactive game with the selected difficulty.",
        "parameters": [{ "$ref": "#/components/parameters/Difficulty" }],
        "responses": { "302": { "description": "Redirect to the interactive Standard game" }, "404": { "description": "Unknown difficulty" } }
      },
      "head": {
        "tags": ["Catalog"],
        "summary": "Read Standard action headers",
        "parameters": [{ "$ref": "#/components/parameters/Difficulty" }],
        "responses": { "302": { "description": "Redirect to the interactive Standard game" }, "404": { "description": "Unknown difficulty" } }
      }
    },
    "/play/standard/{difficulty}/seed/{seed}": {
      "get": {
        "tags": ["Catalog"],
        "summary": "Open a shared-seed Standard game action",
        "description": "A bounded, noindex action URL. It redirects to Standard and never issues a Ranked Challenge ticket.",
        "parameters": [{ "$ref": "#/components/parameters/Difficulty" }, { "$ref": "#/components/parameters/Seed" }],
        "responses": { "302": { "description": "Redirect to the interactive Standard game" }, "404": { "description": "Unknown difficulty or invalid seed" } }
      },
      "head": {
        "tags": ["Catalog"],
        "summary": "Read shared-seed Standard action headers",
        "parameters": [{ "$ref": "#/components/parameters/Difficulty" }, { "$ref": "#/components/parameters/Seed" }],
        "responses": { "302": { "description": "Redirect to the interactive Standard game" }, "404": { "description": "Unknown difficulty or invalid seed" } }
      }
    },
    "/play/ranked/{difficulty}": {
      "get": {
        "tags": ["Catalog"],
        "summary": "Open a clean Ranked Challenge game action",
        "description": "A noindex action URL. It never places a ticket, nonce, seed, or signature in the shared URL.",
        "parameters": [{ "$ref": "#/components/parameters/Difficulty" }],
        "responses": { "302": { "description": "Redirect to the interactive Ranked Challenge entry" }, "404": { "description": "Unknown difficulty" } }
      },
      "head": {
        "tags": ["Catalog"],
        "summary": "Read Ranked Challenge action headers",
        "parameters": [{ "$ref": "#/components/parameters/Difficulty" }],
        "responses": { "302": { "description": "Redirect to the interactive Ranked Challenge entry" }, "404": { "description": "Unknown difficulty" } }
      }
    },
    "/feed.json": {
      "get": { "tags": ["Discovery"], "summary": "Read recent public runs as JSON Feed 1.1", "responses": { "200": { "description": "Privacy-filtered recent-run feed" }, "503": { "description": "Feed temporarily unavailable" } } }
    },
    "/feed.atom": {
      "get": { "tags": ["Discovery"], "summary": "Read recent public runs as Atom", "responses": { "200": { "description": "Privacy-filtered recent-run feed" }, "503": { "description": "Feed temporarily unavailable" } } }
    },
    "/sitemap.xml": {
      "get": { "tags": ["Discovery"], "summary": "Read the top-level static and public-run sitemap index", "responses": { "200": { "description": "XML sitemap index" } } },
      "head": { "tags": ["Discovery"], "summary": "Read top-level sitemap headers", "responses": { "200": { "description": "Sitemap exists" } } }
    },
    "/sitemap-runs.xml": {
      "get": { "tags": ["Discovery"], "summary": "Read the paginated public-run sitemap index", "responses": { "200": { "description": "XML sitemap index" }, "503": { "description": "Sitemap temporarily unavailable" } } },
      "head": { "tags": ["Discovery"], "summary": "Read public-run sitemap-index headers", "responses": { "200": { "description": "Sitemap exists" }, "503": { "description": "Sitemap temporarily unavailable" } } }
    },
    "/sitemap-runs/{page}.xml": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Read one page of canonical public run and guide URLs",
        "parameters": [{ "name": "page", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1 } }],
        "responses": { "200": { "description": "XML URL set" }, "404": { "description": "Sitemap page not found" }, "503": { "description": "Sitemap temporarily unavailable" } }
      },
      "head": {
        "tags": ["Discovery"],
        "summary": "Read public-run sitemap-page headers",
        "parameters": [{ "name": "page", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1 } }],
        "responses": { "200": { "description": "Sitemap page exists" }, "404": { "description": "Sitemap page not found" }, "503": { "description": "Sitemap temporarily unavailable" } }
      }
    }
  },
  "components": {
    "parameters": {
      "RunId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Stable gameplay-hash-derived public run identifier.",
        "schema": { "type": "string", "pattern": "^r_[a-f0-9]{16,32}$" }
      },
      "Difficulty": {
        "name": "difficulty",
        "in": "path",
        "required": true,
        "schema": { "type": "string", "enum": ["apprentice", "journeyman", "master", "grandmaster", "legendary", "impossible"] }
      },
      "Seed": {
        "name": "seed",
        "in": "path",
        "required": true,
        "description": "Unsigned 32-bit Standard-game seed.",
        "schema": { "type": "integer", "minimum": 0, "maximum": 4294967295 }
      }
    }
  }
}
