{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://thehiveryiq.com/.well-known/schemas/proof-transition-portable-v1.json",
  "title": "Proof Transition Portable v1, portable final state proof",
  "description": "Canonical schema for the Hive portable final state proof, canonical type proof.transition.portable. A fixed shape, bandwidth bounded companion to the proof state transition container, canonical type proof.transition. It binds the same run's workflow identity, transition table digest, issuer registry digest, final state, effect gate digest, input count, and a rolling input commitment, into one Ed25519 signature over a recomputable payload_sha256, without listing the inputs array. The receipt attests that the exporting signer asserts these bindings for the named run. It does not independently replay the omitted constituent inputs, and a verifier who needs that replay must obtain and verify the full proof.transition container this proof was exported from.",
  "type": "object",
  "required": [
    "receipt_id",
    "payload_sha256",
    "sig_b64u",
    "key_id",
    "algorithm",
    "ts",
    "signed_body"
  ],
  "additionalProperties": false,
  "properties": {
    "receipt_id": {
      "type": "string",
      "pattern": "^r_proof\\.transition\\.portable_[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._:%-]+$",
      "description": "The exporter's signing key. May differ from the key_id that signed the source proof.transition container; this proof attests to the exporter's assertion of the bindings below, not to a re-signature by the original issuer."
    },
    "algorithm": { "type": "string", "const": "Ed25519" },
    "ts": { "type": "integer", "minimum": 1000000000 },
    "signed_body": {
      "type": "object",
      "description": "Every field here is fixed shape and covered by payload_sha256. This object never grows with the number of inputs the source run admitted.",
      "required": [
        "receipt_type",
        "schema",
        "workflow_id",
        "run_id",
        "source_receipt_id",
        "source_payload_sha256",
        "table_sha256",
        "registry_sha256",
        "final_state",
        "effect_gate_sha256",
        "input_count",
        "input_commitment",
        "boundary"
      ],
      "additionalProperties": false,
      "properties": {
        "receipt_type": { "type": "string", "const": "proof.transition.portable" },
        "schema": { "type": "string", "const": "r1.0.0" },
        "workflow_id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 256,
          "description": "Stable identifier for the workflow this run belongs to. Distinct from run_id, which names one execution of the workflow."
        },
        "run_id": { "type": "string", "minLength": 1, "maxLength": 256 },
        "source_receipt_id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 300,
          "description": "receipt_id of the full proof.transition container this proof was exported from."
        },
        "source_payload_sha256": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$",
          "description": "payload_sha256 of the full proof.transition container's signed_body at export time, binding this portable proof to that exact container."
        },
        "table_sha256": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$",
          "description": "The source container's transition_table.table_sha256, copied verbatim."
        },
        "registry_sha256": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$",
          "description": "The source container's issuer_registry.registry_sha256, copied verbatim."
        },
        "final_state": { "type": "string", "minLength": 1, "maxLength": 128 },
        "effect_gate_sha256": {
          "type": "string",
          "pattern": "^[0-9a-f]{64}$",
          "description": "Digest of the source container's effect_gate object, canonicalised the same way payload_sha256 is computed, so the gate's content is bound without repeating it here."
        },
        "input_count": {
          "type": "integer",
          "minimum": 1,
          "maximum": 4096,
          "description": "The number of admitted inputs in the source container's inputs array."
        },
        "input_commitment": {
          "type": "object",
          "description": "An aggregate commitment over the source container's inputs array, in order, so a holder of the original inputs can check the binding without this proof embedding them.",
          "required": ["scheme", "root_sha256"],
          "additionalProperties": false,
          "properties": {
            "scheme": { "type": "string", "enum": ["merkle_sha256", "sorted_concat_sha256"] },
            "root_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
          }
        },
        "boundary": {
          "type": "string",
          "const": "This receipt attests that the exporting signer named in key_id asserts the workflow_id, table_sha256, registry_sha256, final_state, effect_gate_sha256, input_count, and input_commitment bound here for the run named by run_id, exported from the full proof.transition container named by source_receipt_id and source_payload_sha256. Portable verification authenticates this signed assertion and its internal bindings only. It does not independently replay the omitted constituent inputs, does not verify the source container's own signature, and does not attest that the source container itself still exists or still verifies. A verifier who needs that replay must obtain and verify the full proof.transition container separately."
        }
      }
    }
  }
}
