{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://thehiveryiq.com/.well-known/schemas/supersession-receipt-v1.json",
  "title": "Supersession Receipt v1, correction and supersession receipt",
  "description": "Canonical schema for the Hive correction and supersession receipt, canonical type supersession.receipt. Names one or more superseded receipt digests, the reason, the effective time, the replacement receipt digest, the affected scope, and an immutable chain linkage into one Ed25519 signature over a recomputable payload_sha256. The receipt attests that the named replacement corrects the named superseded receipts as of effective_at. It does not attest that the replacement content is itself correct, and it does not retroactively alter the superseded receipts, which remain independently verifiable exactly as originally signed.",
  "type": "object",
  "required": [
    "receipt_id",
    "payload_sha256",
    "sig_b64u",
    "key_id",
    "algorithm",
    "ts",
    "signed_body"
  ],
  "additionalProperties": false,
  "properties": {
    "receipt_id": {
      "type": "string",
      "pattern": "^r_supersession\\.receipt_[0-9]{10,}_[0-9a-f]{12}$"
    },
    "payload_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
    "sig_b64u": { "type": "string", "pattern": "^[A-Za-z0-9_-]{86}$" },
    "key_id": { "type": "string", "pattern": "^did:(hive|web|key):[A-Za-z0-9._:%-]+$" },
    "algorithm": { "type": "string", "const": "Ed25519" },
    "ts": { "type": "integer", "minimum": 1000000000 },
    "signed_body": {
      "type": "object",
      "required": [
        "receipt_type",
        "schema",
        "correction_id",
        "tenant_id",
        "supersedes",
        "reason_code",
        "reason_detail",
        "effective_at",
        "replacement",
        "affected_scope",
        "boundary"
      ],
      "additionalProperties": false,
      "properties": {
        "receipt_type": { "type": "string", "const": "supersession.receipt" },
        "schema": { "type": "string", "const": "r1.0.0" },
        "correction_id": { "type": "string", "minLength": 1, "maxLength": 256 },
        "tenant_id": { "type": "string", "minLength": 1, "maxLength": 256 },
        "supersedes": {
          "type": "array",
          "minItems": 1,
          "maxItems": 64,
          "description": "The receipt digests this correction supersedes. Every entry names a receipt that must exist and must not itself have already been named as a replacement in an earlier correction that this one's chain_link does not extend, which is what prevents an ambiguous fork.",
          "items": {
            "type": "object",
            "required": ["receipt_id", "payload_sha256"],
            "additionalProperties": false,
            "properties": {
              "receipt_id": { "type": "string", "minLength": 1, "maxLength": 300 },
              "payload_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
            }
          }
        },
        "reason_code": {
          "type": "string",
          "enum": ["factual_error", "computation_error", "policy_change", "data_correction", "withdrawal"]
        },
        "reason_detail": { "type": "string", "minLength": 1, "maxLength": 2048 },
        "effective_at": {
          "type": "string",
          "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}([.][0-9]{1,9})?Z$",
          "description": "When the correction takes effect. Must not precede the issued_at of every superseded receipt, and must not precede this correction's own ts."
        },
        "replacement": {
          "type": "object",
          "description": "The receipt that replaces the superseded set. allow_fork lets a policy explicitly permit more than one open replacement for the same superseded receipt at once; absent that, a second open replacement for an already superseded target is an ambiguous fork.",
          "required": ["receipt_id", "payload_sha256"],
          "additionalProperties": false,
          "properties": {
            "receipt_id": { "type": "string", "minLength": 1, "maxLength": 300 },
            "payload_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
          }
        },
        "affected_scope": {
          "type": "array",
          "minItems": 1,
          "maxItems": 256,
          "items": { "type": "string", "minLength": 1, "maxLength": 256 }
        },
        "allow_fork": {
          "type": "boolean",
          "description": "Defaults to false. When false, a superseded receipt named by more than one non revoked correction is an ambiguous fork. When true, the policy explicitly permits parallel corrections of the same target."
        },
        "chain_link": {
          "type": "object",
          "description": "Absent only for a correction whose supersedes entries have never been corrected before. Present when this correction itself corrects a receipt that was already the replacement in an earlier correction, binding the two corrections into one immutable chain.",
          "required": ["previous_correction_receipt_id", "previous_correction_payload_sha256"],
          "additionalProperties": false,
          "properties": {
            "previous_correction_receipt_id": { "type": "string", "minLength": 1, "maxLength": 300 },
            "previous_correction_payload_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
          }
        },
        "boundary": {
          "type": "string",
          "const": "This receipt attests that the named replacement corrects the receipts named in supersedes as of effective_at, for the reason and scope stated in signed_body. It does not attest that the replacement content is itself correct, and it does not alter the superseded receipts, which remain independently verifiable exactly as originally signed."
        }
      }
    }
  }
}
