{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://thehiveryiq.com/.well-known/schemas/retention-policy-v1.json",
  "title": "Retention Policy Commitment Receipt, v1",
  "description": "Canonical schema for the Hive retention policy commitment receipt, canonical type retention.policy. The instrument records that a party, presented as a salted commitment, fixed a named retention policy at a named version and text digest, with a stated retention period and grace period over a scope presented as a salted commitment, at a recorded commitment instant, and that the recorded effective instant is not earlier than that commitment instant under the declared drift bounds. It exists so that a later deletion event can be placed against a rule that was already recorded, rather than against a document that can be rewritten once the deletion instant is known. The policy text itself never enters the signed body, only its digest.",
  "type": "object",
  "required": [
    "receipt_id",
    "payload_sha256",
    "sig_b64u",
    "key_id",
    "algorithm",
    "ts",
    "signed_body"
  ],
  "additionalProperties": false,
  "properties": {
    "receipt_id": { "type": "string", "pattern": "^r_retention[.]policy_[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",
        "policy_id",
        "policy_version",
        "policy_digest",
        "retention_period_days",
        "grace_period_days",
        "scope_commitment",
        "salt_commitment",
        "committer_commitment",
        "effective_from",
        "committed_at",
        "boundary"
      ],
      "additionalProperties": false,
      "properties": {
        "receipt_type": { "type": "string", "const": "retention.policy" },
        "schema": { "type": "string", "const": "r1.0.0" },
        "policy_id": { "type": "string", "pattern": "^pol_[0-9a-z][0-9a-z._-]{0,47}$" },
        "policy_version": { "type": "string", "pattern": "^[0-9a-zA-Z][0-9a-zA-Z._-]{0,31}$" },
        "policy_digest": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$",
          "description": "Lowercase hex SHA-256 over the policy text as published. The text is never carried here."
        },
        "retention_period_days": {
          "type": "integer",
          "minimum": 0,
          "maximum": 36500,
          "description": "Days the policy version keeps a covered object before deletion is due. A recorded zero is accepted by this schema and refused by the PERIOD_BOUNDS gate, so the refusal names the rule rather than the field."
        },
        "grace_period_days": {
          "type": "integer",
          "minimum": 0,
          "maximum": 3650,
          "description": "Days after the due instant that the policy version still allowed for execution."
        },
        "scope_commitment": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$",
          "description": "Salted commitment over the scope descriptor, built with the same construction the retention purge receipt uses, so one disclosed salt and one descriptor open both receipts to the same value."
        },
        "salt_commitment": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
        "committer_commitment": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$",
          "description": "Salted commitment over the descriptor of the party that recorded the policy. No party is named here."
        },
        "effective_from": {
          "type": "object",
          "required": ["utc", "drift_seconds"],
          "additionalProperties": false,
          "properties": {
            "utc": { "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$" },
            "drift_seconds": { "type": "integer", "minimum": 0, "maximum": 86400 }
          }
        },
        "committed_at": {
          "type": "object",
          "required": ["utc", "drift_seconds"],
          "additionalProperties": false,
          "properties": {
            "utc": { "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$" },
            "drift_seconds": { "type": "integer", "minimum": 0, "maximum": 86400 }
          }
        },
        "boundary": {
          "type": "string",
          "minLength": 1,
          "const": "This receipt attests only that a party, presented as a salted commitment, recorded a retention policy text at the named policy identifier, version, and text digest, with the recorded retention period and grace period over a scope presented as a salted commitment, at the recorded commitment instant, and that the recorded effective instant is not earlier than that commitment instant under the declared drift bounds. It does not establish that the policy text is adequate for any purpose, that it is lawful in any place, that any authority read it or accepted it, that it was ever applied to any record, or that any deletion it describes happened. Whether a later deletion event is consistent_with this recorded policy is the question a separate retention purge receipt asks, and this receipt answers none of it. The policy text itself never enters this receipt, and the recorded periods and instants are presented as reported by the recording party."
        }
      }
    }
  }
}
