{
  "$id": "https://scholar-sidekick.com/.well-known/sources.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Scholar Sidekick - sources.json",
  "description": "Schema for Scholar Sidekick's authoritative data-source manifest. Documents the resolver chain (with fallback order) per identifier type, deterministic-output guarantees, and operational policy. Lives at /.well-known/sources.json.",
  "type": "object",
  "required": ["service", "service_url", "version", "transform_version", "openapi", "resolvers"],
  "additionalProperties": false,
  "properties": {
    "$schema": {
      "type": "string",
      "format": "uri",
      "description": "URI of this JSON Schema document."
    },
    "service": {
      "type": "string",
      "description": "Stable service identifier (e.g. \"scholar-sidekick\")."
    },
    "service_url": {
      "type": "string",
      "format": "uri",
      "description": "Canonical service URL."
    },
    "version": {
      "type": "string",
      "description": "Manifest version (typically a date string)."
    },
    "transform_version": {
      "type": "string",
      "description": "Mirrors the value returned in the x-scholar-transform-version response header. Identical inputs at a fixed transform_version produce byte-identical output."
    },
    "openapi": {
      "type": "string",
      "format": "uri",
      "description": "URL to the canonical OpenAPI specification."
    },
    "documentation": {
      "type": "string",
      "format": "uri"
    },
    "principles": {
      "type": "string",
      "format": "uri"
    },
    "verification_url": {
      "type": "string",
      "format": "uri",
      "description": "URL to a copy-paste verification kit that lets external evaluators independently verify determinism, provenance, and edge-case claims against the live API."
    },
    "changelog_url": {
      "type": "string",
      "format": "uri",
      "description": "URL to the human- and agent-readable changelog enumerating transform_version bumps and notable changes, each tagged breaking / output-affecting / non-breaking."
    },
    "status_url": {
      "type": "string",
      "format": "uri",
      "description": "URL to the public status/uptime page. Headline status reflects Scholar Sidekick's own API availability with rolling uptime and incident history; upstream-source health is reported in a separate, clearly-labelled informational section."
    },
    "description": {
      "type": "string"
    },
    "resolvers": {
      "type": "object",
      "description": "Per-identifier-type resolver chain. Keys are identifier type names (doi, pmid, pmcid, isbn, issn, eissn, arxiv, ads, iris, scholarly_url, etc.).",
      "additionalProperties": {
        "type": "object",
        "required": ["chain", "primary_host"],
        "additionalProperties": false,
        "properties": {
          "chain": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Resolver names consulted in fixed order; first non-empty record wins."
          },
          "primary_host": {
            "type": "string",
            "description": "Canonical primary upstream host (allowlisted)."
          },
          "fallbacks": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Allowlisted fallback hosts in order."
          },
          "notes": {
            "type": "string",
            "description": "Human-readable notes on the resolver semantics."
          }
        }
      }
    },
    "guarantees": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "deterministic": {
          "type": "string",
          "description": "Statement of the deterministic-output contract."
        },
        "provenance_headers": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Response headers that surface request-level provenance."
        },
        "network_safety": {
          "type": "string",
          "description": "Statement of outbound-fetch safety guarantees (allowlisting, timeouts, retries, size caps)."
        },
        "ssrf_protection": {
          "type": "string",
          "description": "Statement of SSRF protection policy."
        }
      }
    },
    "provenance_schema": {
      "type": "object",
      "description": "Shape of the opt-in per-item _provenance object (?provenance=1 | full | conflicts).",
      "additionalProperties": false,
      "properties": {
        "description": { "type": "string" },
        "activation": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "query_param": { "type": "string" },
            "values": { "type": "array", "items": { "type": "string" } },
            "header": { "type": "string" }
          }
        },
        "fields": {
          "type": "object",
          "description": "Field name → human-readable description of each _provenance field.",
          "additionalProperties": { "type": "string" }
        }
      }
    },
    "policy": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "cache_strategy": {
          "type": "string"
        },
        "rate_limiting": {
          "type": "string"
        },
        "error_envelope": {
          "type": "string"
        }
      }
    },
    "contact": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "email": {
          "type": "string",
          "format": "email"
        },
        "issues": {
          "type": "string",
          "format": "uri"
        }
      }
    }
  }
}
