{
  "openapi": "3.0.3",
  "info": {
    "title": "paperiswrong public API",
    "version": "0.1.0",
    "description": "Public read-only REST API for paperiswrong.com. Verdicts, claim citations, validator health, anchor self-test, and embeddable badges. See https://yourpaperiswrong.com/api for human-readable docs. PRD §19.1.",
    "license": {
      "name": "MIT (API spec)",
      "url": "https://github.com/adrianaoun/YourPaperIsWrong.com/blob/main/LICENSE"
    },
    "contact": {
      "name": "paperiswrong",
      "url": "https://yourpaperiswrong.com",
      "email": "ops@yourpaperiswrong.com"
    }
  },
  "servers": [
    {
      "url": "https://yourpaperiswrong.com/api/v1",
      "description": "Production"
    }
  ],
  "paths": {
    "/validator": {
      "get": {
        "summary": "Validator + anchor summary stats",
        "description": "Total verdicts, claim-citation coverage, protocol-match histogram, and anchor health summary. Mirrors the /validator transparency page.",
        "responses": {
          "200": {
            "description": "Validator stats payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidatorStats"
                }
              }
            }
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/anchors": {
      "get": {
        "summary": "Per-anchor health detail",
        "description": "Every curated anchor with expected value, latest measurement, delta, and state (healthy / drift / fallback / no-data). Mirrors /anchors.",
        "responses": {
          "200": {
            "description": "Anchor list + summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnchorsPayload"
                }
              }
            }
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/timeline": {
      "get": {
        "summary": "Chronological event feed",
        "description": "Time-sorted verdicts + retractions. Mirrors /timeline.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Max events (default 50, max 200)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "kind",
            "in": "query",
            "description": "Filter to a single event kind",
            "schema": {
              "type": "string",
              "enum": [
                "verdict",
                "retraction"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Time-sorted event feed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelinePayload"
                }
              }
            }
          },
          "400": {
            "description": "Invalid limit or kind",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/retractions": {
      "get": {
        "summary": "Public retraction log",
        "description": "Every retraction with original-label, reason, audit thread, rollback PR, and per-paper /diff link.",
        "responses": {
          "200": {
            "description": "Retraction list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RetractionsPayload"
                }
              }
            }
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/skipped": {
      "get": {
        "summary": "Refusal transparency (papers we did not reproduce)",
        "description": "Papers with a CURRENT POST verdict of `not_attempted` or `out_of_budget`. Completes the self-correction quadrant alongside /validator (C1+C2 gates), /anchors (runtime drift), and /retractions (historical false positives).",
        "responses": {
          "200": {
            "description": "Skipped list + summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SkippedPayload"
                }
              }
            }
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/drivers": {
      "get": {
        "summary": "Driver catalogue (driver-centric corpus view)",
        "description": "One entry per `scripts/run-reproduction-*.ts` file: AGENT_VERSION, ARXIV_ID, MODEL_NAME (HuggingFace path), TITLE (paper title), PROTOCOL_MATCH tier, static CLAIM_CITATION summary, and status (active / retracted / closed-weights / scaffolding / needs-fix). Driver-centric — complements the paper-centric /papers and the event-centric /verdicts.",
        "responses": {
          "200": {
            "description": "Driver list + summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DriversPayload"
                }
              }
            }
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/claims": {
      "get": {
        "summary": "Claim-level checks",
        "description": "One item per structured claim citation attached to a current POST reproduction. Use this for the exact table value, metric, sentence, or quoted span that was checked.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Claim checks list + summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClaimsPayload"
                }
              }
            }
          },
          "400": {
            "description": "Invalid limit"
          },
          "503": {
            "description": "DB unavailable"
          }
        },
        "tags": [
          "claims"
        ]
      }
    },
    "/verdicts": {
      "get": {
        "summary": "Verdict stream",
        "description": "Recent POST verdicts, optionally filtered.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Verdicts payload"
          }
        },
        "tags": [
          "verdicts"
        ]
      }
    },
    "/leaderboards/{kind}": {
      "get": {
        "summary": "Leaderboard rollup by kind",
        "description": "Replication leaderboard. `kind` is one of `labs`, `authors`, or `conferences`. Aggregated across every published POST verdict.",
        "parameters": [
          {
            "name": "kind",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "labs",
                "authors",
                "conferences"
              ]
            }
          },
          {
            "name": "metric",
            "in": "query",
            "description": "reproduction_rate | partial_rate | citation_weighted_rate",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_papers",
            "in": "query",
            "description": "Floor on entries (default 5, 2 for authors)",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Leaderboard payload"
          },
          "400": {
            "description": "Unknown kind"
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/search": {
      "get": {
        "summary": "Paper search by title",
        "description": "Case-insensitive substring match on `papers.title`. v0.1 is title-only ILIKE with fixed limit 20; hybrid lexical + embedding ranking lands in v1.1.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search query, ≤200 chars",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search results"
          },
          "400": {
            "description": "Missing or over-length q"
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/papers": {
      "get": {
        "summary": "Paginated corpus list (paper-centric)",
        "description": "One row per paper indexed by paperiswrong, with the current POST verdict joined in (or null). Use this — not /verdicts — to enumerate the corpus from a third-party dashboard, since /verdicts mixes POST + PRE rows and pages on verdict ids.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated verdict statuses. `none` filters to papers with no current POST verdict."
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter to papers with matching `primary_category` (e.g. cs.CL)."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque keyset cursor from a previous response's `next_cursor`."
          }
        ],
        "responses": {
          "200": {
            "description": "Paper list"
          },
          "400": {
            "description": "Invalid status/limit/cursor"
          },
          "503": {
            "description": "DB unavailable"
          }
        },
        "tags": [
          "papers"
        ]
      }
    },
    "/papers/{arxiv_id}": {
      "get": {
        "summary": "Paper detail",
        "description": "Fetch a paper + its current POST/PRE verdicts + the latest reproduction job + the claim citation that gated it.",
        "parameters": [
          {
            "name": "arxiv_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}\\.[0-9]{4,5}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paper detail"
          },
          "400": {
            "description": "Invalid arxiv_id"
          },
          "404": {
            "description": "Paper not in corpus"
          }
        },
        "tags": [
          "papers"
        ]
      }
    },
    "/papers/{arxiv_id}/badge.json": {
      "get": {
        "summary": "JSON-shaped badge data (shields.io vocab)",
        "description": "Structured fields for the paper's current verdict — { label, message, color, ... }. Drop into shields.io dynamic-JSON-badge templates or custom dashboard widgets.",
        "parameters": [
          {
            "name": "arxiv_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}\\.[0-9]{4,5}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Badge JSON payload"
          }
        },
        "tags": [
          "papers",
          "badge"
        ]
      }
    },
    "/papers/{arxiv_id}/badge.svg": {
      "get": {
        "summary": "Embeddable SVG verdict badge",
        "description": "Shields.io-style SVG showing the paper's current verdict. Drop into HF model cards, GitHub READMEs, lab dashboards. Cross-origin embeddable.",
        "parameters": [
          {
            "name": "arxiv_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}\\.[0-9]{4,5}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SVG badge",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "tags": [
          "papers",
          "badge"
        ]
      }
    },
    "/health": {
      "get": {
        "summary": "Health probe",
        "description": "Returns { ok, db, timestamp }. db = 'reachable' | 'unreachable'.",
        "responses": {
          "200": {
            "description": "Health snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        },
        "tags": [
          "platform"
        ]
      }
    },
    "/agents/prompts": {
      "get": {
        "summary": "Verbatim agent system prompts",
        "description": "JSON mirror of /agents/prompts. Returns the H1 title, the source-of-truth file path, and one entry per H2 section (agent: auditor|predictor|reviewer|reader|notifier|null). PRD §16 — published on purpose.",
        "responses": {
          "200": {
            "description": "Agent-prompts document",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentPrompts"
                }
              }
            }
          }
        },
        "tags": [
          "platform"
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "ValidatorStats": {
        "type": "object",
        "properties": {
          "totalVerdicts": {
            "type": "integer",
            "nullable": true
          },
          "withClaimCitation": {
            "type": "integer",
            "nullable": true
          },
          "protocolMatch": {
            "type": "object",
            "nullable": true,
            "properties": {
              "exact": {
                "type": "integer"
              },
              "proxy": {
                "type": "integer"
              },
              "unknown": {
                "type": "integer"
              },
              "null": {
                "type": "integer"
              }
            }
          },
          "retractionsCount": {
            "type": "integer"
          },
          "publicWrongCount": {
            "type": "integer",
            "nullable": true
          },
          "anchors": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "healthy": {
                "type": "integer"
              },
              "drift": {
                "type": "integer"
              },
              "fallback": {
                "type": "integer"
              },
              "noData": {
                "type": "integer"
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AnchorsPayload": {
        "type": "object",
        "properties": {
          "anchors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Anchor"
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "healthy": {
                "type": "integer"
              },
              "drift": {
                "type": "integer"
              },
              "fallback": {
                "type": "integer"
              },
              "no_data": {
                "type": "integer"
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Anchor": {
        "type": "object",
        "properties": {
          "arxiv_id": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "model_name": {
            "type": "string"
          },
          "section": {
            "type": "string"
          },
          "row": {
            "type": "string"
          },
          "column": {
            "type": "string"
          },
          "expected_value": {
            "type": "number"
          },
          "expected_metric": {
            "type": "string"
          },
          "tolerance": {
            "type": "number"
          },
          "rationale": {
            "type": "string",
            "nullable": true
          },
          "measured": {
            "type": "number",
            "nullable": true
          },
          "delta": {
            "type": "number",
            "nullable": true
          },
          "state": {
            "type": "string",
            "enum": [
              "healthy",
              "drift",
              "fallback",
              "stale",
              "no-data"
            ]
          },
          "computed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "agent_version": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "TimelinePayload": {
        "type": "object",
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/VerdictEvent"
                },
                {
                  "$ref": "#/components/schemas/RetractionEvent"
                }
              ]
            }
          },
          "counts": {
            "type": "object",
            "properties": {
              "verdicts": {
                "type": "integer",
                "nullable": true
              },
              "retractions": {
                "type": "integer"
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "VerdictEvent": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "verdict"
            ]
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "arxiv_id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "agent_version": {
            "type": "string"
          },
          "protocol_match": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RetractionEvent": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "retraction"
            ]
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "arxiv_id": {
            "type": "string"
          },
          "paper_title": {
            "type": "string"
          },
          "original_label": {
            "type": "string"
          },
          "retracted_to": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "RetractionsPayload": {
        "type": "object",
        "properties": {
          "retractions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Retraction"
            }
          },
          "count": {
            "type": "integer"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Retraction": {
        "type": "object",
        "properties": {
          "arxiv_id": {
            "type": "string"
          },
          "paper_title": {
            "type": "string"
          },
          "original_label": {
            "type": "string"
          },
          "original_agent_version": {
            "type": "string"
          },
          "original_verdict_id": {
            "type": "string",
            "nullable": true
          },
          "retracted_on": {
            "type": "string",
            "format": "date"
          },
          "retracted_to": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "audit_href": {
            "type": "string"
          },
          "rollback_pr_url": {
            "type": "string"
          },
          "diff_href": {
            "type": "string"
          }
        }
      },
      "Health": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "db": {
            "type": "string",
            "enum": [
              "reachable",
              "unreachable"
            ]
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "SkippedPayload": {
        "type": "object",
        "properties": {
          "summary": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "not_attempted": {
                "type": "integer"
              },
              "out_of_budget": {
                "type": "integer"
              }
            }
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "arxiv_id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "primary_category": {
                  "type": "string",
                  "nullable": true
                },
                "venue": {
                  "type": "string",
                  "nullable": true
                },
                "reason": {
                  "type": "string",
                  "enum": [
                    "not_attempted",
                    "out_of_budget"
                  ]
                },
                "computed_at": {
                  "type": "string",
                  "nullable": true,
                  "format": "date-time"
                },
                "agent_version": {
                  "type": "string"
                },
                "rationale": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "DriversPayload": {
        "type": "object",
        "properties": {
          "summary": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "active": {
                "type": "integer"
              },
              "retracted": {
                "type": "integer"
              },
              "closed_weights": {
                "type": "integer"
              },
              "scaffolding": {
                "type": "integer"
              },
              "needs_fix": {
                "type": "integer"
              },
              "by_protocol": {
                "type": "object",
                "properties": {
                  "exact": {
                    "type": "integer"
                  },
                  "proxy": {
                    "type": "integer"
                  },
                  "unknown": {
                    "type": "integer"
                  },
                  "null": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string"
                },
                "file_name": {
                  "type": "string"
                },
                "agent_version": {
                  "type": "string",
                  "nullable": true
                },
                "arxiv_id": {
                  "type": "string",
                  "nullable": true
                },
                "title": {
                  "type": "string",
                  "nullable": true
                },
                "model_name": {
                  "type": "string",
                  "nullable": true
                },
                "protocol_match": {
                  "type": "string",
                  "nullable": true,
                  "enum": [
                    "exact",
                    "proxy",
                    "unknown",
                    null
                  ]
                },
                "claim_citation": {
                  "type": "object",
                  "nullable": true,
                  "properties": {
                    "section": {
                      "type": "string",
                      "nullable": true
                    },
                    "row": {
                      "type": "string",
                      "nullable": true
                    },
                    "column": {
                      "type": "string",
                      "nullable": true
                    },
                    "reportedValue": {
                      "type": "number",
                      "nullable": true
                    },
                    "reportedMetric": {
                      "type": "string",
                      "nullable": true
                    },
                    "quotedText": {
                      "type": "string",
                      "nullable": true
                    },
                    "pdfPage": {
                      "type": "integer",
                      "nullable": true
                    }
                  }
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "retracted",
                    "closed-weights",
                    "scaffolding",
                    "needs-fix"
                  ]
                },
                "status_reason": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "ClaimsPayload": {
        "type": "object",
        "properties": {
          "summary": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "verified": {
                "type": "integer"
              },
              "partially_supported": {
                "type": "integer"
              },
              "not_reproduced": {
                "type": "integer"
              },
              "not_checkable": {
                "type": "integer"
              },
              "ambiguous": {
                "type": "integer"
              }
            }
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClaimCheck"
            }
          }
        }
      },
      "ClaimCheck": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "claim_text": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "verified",
              "partially_supported",
              "not_reproduced",
              "not_checkable",
              "ambiguous"
            ]
          },
          "verdict_status": {
            "type": "string"
          },
          "confidence": {
            "type": "number",
            "nullable": true
          },
          "score": {
            "type": "number",
            "nullable": true
          },
          "computed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "agent_version": {
            "type": "string"
          },
          "job_id": {
            "type": "string",
            "nullable": true
          },
          "paper": {
            "type": "object",
            "properties": {
              "arxiv_id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "venue": {
                "type": "string",
                "nullable": true
              },
              "primary_category": {
                "type": "string",
                "nullable": true
              },
              "url": {
                "type": "string"
              }
            }
          },
          "citation": {
            "type": "object",
            "properties": {
              "paper_arxiv_id": {
                "type": "string"
              },
              "section": {
                "type": "string",
                "nullable": true
              },
              "row": {
                "type": "string",
                "nullable": true
              },
              "column": {
                "type": "string",
                "nullable": true
              },
              "reported_value": {
                "type": "number",
                "nullable": true
              },
              "reported_metric": {
                "type": "string",
                "nullable": true
              },
              "quoted_text": {
                "type": "string",
                "nullable": true
              },
              "pdf_page": {
                "type": "integer",
                "nullable": true
              },
              "notes": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "protocol_match": {
            "type": "string",
            "nullable": true,
            "enum": [
              "exact",
              "proxy",
              "unknown",
              null
            ]
          }
        }
      },
      "AgentPrompts": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "sections": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "slug": {
                  "type": "string"
                },
                "agent": {
                  "type": "string",
                  "nullable": true,
                  "enum": [
                    "auditor",
                    "predictor",
                    "reviewer",
                    "reader",
                    "notifier",
                    null
                  ]
                },
                "version": {
                  "type": "string",
                  "nullable": true
                },
                "body": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "platform",
      "description": "Platform-wide stats and self-test"
    },
    {
      "name": "claims",
      "description": "Claim-level checks"
    },
    {
      "name": "verdicts",
      "description": "Verdict stream and feeds"
    },
    {
      "name": "papers",
      "description": "Per-paper detail"
    },
    {
      "name": "badge",
      "description": "Embeddable widgets"
    }
  ]
}