{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://databutler.dev/schema/fact.v0.json",
  "title": "Verified Facts record (verified-facts/0.2)",
  "description": "One official figure by key, with its period, official source, verification date, claim hash and (L3) detached Ed25519 signature. Specification: https://databutler.dev/protocol/facts §4. status, ageDays and maxAgeDays are required of a server-filtering (L2) publisher and absent from a static (L1, filtering: client) record, so the conformance checker enforces them rather than this schema. Publishers may add fields; consumers ignore unknown ones.",
  "type": "object",
  "required": [
    "protocol",
    "key",
    "label",
    "value",
    "unit",
    "period",
    "effectiveFrom",
    "effectiveTo",
    "source",
    "verifiedDate",
    "hash",
    "publisher"
  ],
  "properties": {
    "protocol": {
      "const": "verified-facts/0.2"
    },
    "key": {
      "$ref": "#/$defs/key"
    },
    "requestedKey": {
      "type": "string",
      "description": "The key as requested, when it was an alias or auto-resolved."
    },
    "resolved": {
      "type": "object",
      "required": [
        "score",
        "matched"
      ],
      "properties": {
        "score": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "matched": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "aliases": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "label": {
      "type": "string",
      "minLength": 1
    },
    "value": {
      "description": "The figure: number, string, boolean, object, array, or null only with withdrawn."
    },
    "unit": {
      "type": [
        "string",
        "null"
      ]
    },
    "period": {
      "type": [
        "string",
        "null"
      ],
      "description": "The publisher's period label (2026-27, 2026, summer-2027) or null for a standing figure."
    },
    "effectiveFrom": {
      "type": [
        "string",
        "null"
      ],
      "format": "date"
    },
    "effectiveTo": {
      "type": [
        "string",
        "null"
      ],
      "format": "date"
    },
    "source": {
      "type": "string",
      "format": "uri",
      "pattern": "^https://"
    },
    "sourceType": {
      "enum": [
        "authority",
        "methodology",
        "derived"
      ]
    },
    "quote": {
      "type": "string"
    },
    "verifiedDate": {
      "type": "string",
      "format": "date"
    },
    "nextScheduledRefresh": {
      "type": [
        "string",
        "null"
      ],
      "format": "date"
    },
    "status": {
      "enum": [
        "fresh",
        "stale"
      ]
    },
    "ageDays": {
      "type": "integer",
      "minimum": 0
    },
    "maxAgeDays": {
      "type": [
        "integer",
        "null"
      ],
      "minimum": 0
    },
    "previous": {
      "type": "object",
      "required": [
        "value",
        "period"
      ],
      "properties": {
        "value": {},
        "period": {
          "type": [
            "string",
            "null"
          ]
        },
        "effectiveFrom": {
          "type": "string",
          "format": "date"
        },
        "source": {
          "type": "string",
          "format": "uri"
        }
      }
    },
    "scope": {
      "type": "string"
    },
    "withdrawn": {
      "type": "string",
      "format": "date"
    },
    "supersededBy": {
      "type": "string"
    },
    "hash": {
      "type": "string",
      "pattern": "^sha256:[0-9a-f]{64}$"
    },
    "signature": {
      "$ref": "#/$defs/signature"
    },
    "publisher": {
      "$ref": "#/$defs/publisher"
    },
    "cite": {
      "type": "object",
      "required": [
        "url"
      ],
      "properties": {
        "url": {
          "type": "string",
          "format": "uri"
        },
        "text": {
          "type": "string"
        }
      }
    }
  },
  "$defs": {
    "key": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9-]*(/[a-z0-9][a-z0-9.-]*){1,5}$",
      "description": "Two to six lowercase slash-separated segments (spec §3.1)."
    },
    "publisher": {
      "type": "object",
      "required": [
        "name",
        "url"
      ],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1
        },
        "url": {
          "type": "string",
          "format": "uri"
        }
      }
    },
    "signature": {
      "type": "object",
      "required": [
        "alg",
        "kid",
        "jws",
        "keys"
      ],
      "properties": {
        "alg": {
          "const": "EdDSA"
        },
        "kid": {
          "type": "string",
          "minLength": 1
        },
        "jws": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]+\\.\\.[A-Za-z0-9_-]+$",
          "description": "Detached compact JWS (RFC 7515 Appendix F) over the JCS attestation (spec §8.3)."
        },
        "keys": {
          "type": "string",
          "format": "uri",
          "description": "The JWK Set URL."
        }
      }
    },
    "candidate": {
      "type": "object",
      "required": [
        "key",
        "label",
        "unit",
        "period",
        "verifiedDate",
        "score",
        "matched"
      ],
      "properties": {
        "key": {
          "$ref": "#/$defs/key"
        },
        "label": {
          "type": "string"
        },
        "unit": {
          "type": [
            "string",
            "null"
          ]
        },
        "period": {
          "type": [
            "string",
            "null"
          ]
        },
        "verifiedDate": {
          "type": "string",
          "format": "date"
        },
        "score": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "matched": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "miss": {
      "title": "A miss (spec §5.4)",
      "type": "object",
      "required": [
        "protocol",
        "covered"
      ],
      "properties": {
        "protocol": {
          "const": "verified-facts/0.2"
        },
        "covered": {
          "const": false
        },
        "error": {
          "type": "string"
        },
        "requestedKey": {
          "type": "string"
        },
        "key": {
          "$ref": "#/$defs/key"
        },
        "candidates": {
          "type": "array",
          "maxItems": 5,
          "items": {
            "$ref": "#/$defs/candidate"
          }
        },
        "index": {
          "type": "string",
          "format": "uri"
        },
        "periodsHeld": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "batch": {
      "title": "A batch answer (spec §7)",
      "type": "object",
      "required": [
        "protocol",
        "publisher",
        "count",
        "results",
        "status"
      ],
      "properties": {
        "protocol": {
          "const": "verified-facts/0.2"
        },
        "publisher": {
          "$ref": "#/$defs/publisher"
        },
        "count": {
          "type": "integer",
          "minimum": 0
        },
        "results": {
          "type": "array",
          "maxItems": 50,
          "items": {
            "type": "object"
          }
        },
        "status": {
          "enum": [
            "fresh",
            "stale"
          ]
        }
      }
    },
    "index": {
      "title": "The key index (spec §5.5)",
      "type": "object",
      "required": [
        "protocol",
        "publisher",
        "count",
        "generated",
        "facts"
      ],
      "properties": {
        "protocol": {
          "const": "verified-facts/0.2"
        },
        "publisher": {
          "$ref": "#/$defs/publisher"
        },
        "count": {
          "type": "integer",
          "minimum": 0
        },
        "generated": {
          "type": "string",
          "format": "date"
        },
        "facts": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "key",
              "label",
              "unit",
              "period",
              "verifiedDate",
              "hash"
            ],
            "properties": {
              "key": {
                "$ref": "#/$defs/key"
              },
              "label": {
                "type": "string"
              },
              "unit": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "period": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "verifiedDate": {
                "type": "string",
                "format": "date"
              },
              "hash": {
                "type": "string",
                "pattern": "^sha256:[0-9a-f]{64}$"
              },
              "aliases": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "resolve": {
      "title": "A resolve answer (spec §6.2)",
      "type": "object",
      "required": [
        "protocol",
        "query",
        "candidates"
      ],
      "properties": {
        "protocol": {
          "const": "verified-facts/0.2"
        },
        "query": {
          "type": "string"
        },
        "candidates": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/candidate"
          }
        },
        "best": {
          "type": "object"
        },
        "hint": {
          "type": "string"
        }
      }
    }
  }
}
