{
  "$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."
    },
    "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."
        }
      }
    },
    "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" }
      }
    }
  }
}
