{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://www.citegraph.app/schemas/citation-measurement.schema.json",
  "title": "AI citation measurement record",
  "description": "One measurement of how AI assistants answer a set of buyer questions about a product. Published by CiteGraph so anyone can record, share or reproduce a measurement in the same shape. Rates are 0..1; margins are in percentage points.",
  "type": "object",
  "required": ["product", "questions", "engines", "runsPerQuestion", "answers", "summary"],
  "properties": {
    "product": {
      "type": "object",
      "required": ["name", "domain"],
      "properties": {
        "name": { "type": "string", "description": "The product name as a buyer would write it." },
        "domain": { "type": "string", "description": "Root domain, used to decide whether a cited page is the product's own." },
        "category": { "type": "string" },
        "competitors": { "type": "array", "items": { "type": "string" } }
      }
    },
    "measuredAt": { "type": "string", "format": "date-time" },
    "questions": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": ["id", "text"],
        "properties": {
          "id": { "type": "string" },
          "text": { "type": "string", "description": "The question exactly as it was sent, in the buyer's words." },
          "intent": { "type": "string", "enum": ["recommendation", "alternatives", "pricing", "problem", "comparison"] }
        }
      }
    },
    "engines": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": ["id", "label"],
        "properties": {
          "id": { "type": "string" },
          "label": { "type": "string" },
          "model": { "type": "string", "description": "The model or API used, so the reader can tell a consumer app from an API call." },
          "webSearch": { "type": "boolean" }
        }
      }
    },
    "runsPerQuestion": { "type": "integer", "minimum": 1, "description": "How many times each question was asked of each engine. One is a screenshot, not a measurement." },
    "answers": {
      "type": "array",
      "description": "One record per question × engine × run. Failed calls are recorded with ok=false and excluded from every denominator.",
      "items": {
        "type": "object",
        "required": ["questionId", "engine", "run", "ok"],
        "properties": {
          "questionId": { "type": "string" },
          "engine": { "type": "string" },
          "run": { "type": "integer", "minimum": 1 },
          "ok": { "type": "boolean" },
          "text": { "type": "string", "description": "The answer verbatim. Keep it; every rate should be checkable against it." },
          "named": { "type": "boolean", "description": "The product appears in the answer's prose, tested with URLs stripped." },
          "cited": { "type": "boolean", "description": "A page on the product's own domain is among the answer's sources." },
          "productsNamed": { "type": "array", "items": { "type": "string" } },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["domain"],
              "properties": {
                "domain": { "type": "string", "description": "The true source host, with any grounding-redirect wrapper unwrapped." },
                "url": { "type": "string" },
                "kind": { "type": "string", "enum": ["listicle", "review-platform", "community", "directory", "wikipedia", "news", "youtube", "social", "own-site", "competitor", "docs", "other"] }
              }
            }
          }
        }
      }
    },
    "summary": {
      "type": "object",
      "required": ["answersCount", "namedRate", "citedRate"],
      "properties": {
        "answersCount": { "type": "integer", "description": "Answers with ok=true." },
        "namedRate": { "type": "number", "minimum": 0, "maximum": 1 },
        "namedMargin": { "type": "number", "description": "Half-width of the 95% interval on namedRate, in percentage points." },
        "citedRate": { "type": "number", "minimum": 0, "maximum": 1 },
        "citedMargin": { "type": "number" },
        "questionsNamed": { "type": "integer", "description": "Questions where the product was named in at least one answer." },
        "perEngine": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["engine", "answers", "namedRate"],
            "properties": {
              "engine": { "type": "string" },
              "answers": { "type": "integer" },
              "namedRate": { "type": "number" },
              "citedRate": { "type": "number" }
            }
          }
        },
        "blindSpots": {
          "type": "array",
          "description": "Questions where the product was never named, with what won instead and the rate the product would reach if it won that question.",
          "items": {
            "type": "object",
            "required": ["questionId"],
            "properties": {
              "questionId": { "type": "string" },
              "namedInstead": { "type": "array", "items": { "type": "string" } },
              "topSources": { "type": "array", "items": { "type": "string" } },
              "ifWonRate": { "type": "number", "minimum": 0, "maximum": 1 }
            }
          }
        }
      }
    }
  }
}
