{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raven-launch-console.vercel.app/receipt-wire-schema.json",
  "title": "Raven Wire Receipt",
  "description": "Schema for the signed receipt object as returned by POST /verify and as published in /receipt-test-vector.json (vector.receipt). THIS is the schema to validate the receipt object itself. For persisting receipts in agent memory or storage backends, use the storage envelope schema at /receipt-schema.json (which wraps this object as rawResponse). The signing contract is unchanged by this schema: the ed25519 signature covers the canonical preimage recipe published in the test vector (expected.signature_preimage_recipe), not this document.",
  "$comment": "Forward-compatible: additionalProperties stays true so future informational fields do not break third-party validators. The one hard prohibition: 'unsigned' must NEVER appear inside the receipt object. In the live POST /verify response body, 'unsigned' appears as a sibling key alongside the receipt fields — the receipt object that this schema validates is the response body WITH the top-level 'unsigned' annotation removed (exactly how the test vector separates vector.receipt from vector.unsigned). The unsigned annotation carries no receipt authority.",
  "type": "object",
  "required": [
    "ok",
    "verdict",
    "findingCodes",
    "coverageGaps",
    "engineVersion",
    "replayHash",
    "officialAttestationHash",
    "keyId",
    "issuedAt",
    "signature",
    "signatureAlg"
  ],
  "properties": {
    "ok": { "type": "boolean" },
    "verdict": {
      "enum": ["pass", "pass_with_info_finding", "warning", "risk", "unknowable"]
    },
    "engineOutcome": { "type": "string" },
    "reason": { "type": "string" },
    "findingCodes": {
      "type": "array",
      "items": { "type": "string" }
    },
    "triggeringFindingCodes": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Finding codes that determined the verdict. Informational-only evidence (e.g. launch.*) must never appear here."
    },
    "findings": {
      "type": "array",
      "items": { "type": "object" }
    },
    "coverageGaps": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Normative. Must never be summarized away. The authoritative limitation list for this receipt."
    },
    "replayable": { "type": "boolean" },
    "rpc": {
      "type": "object",
      "description": "Read context for the verification. observedSlot lives HERE (rpc.observedSlot), not at the receipt top level.",
      "properties": {
        "commitment": { "type": "string" },
        "mintAddress": { "type": "string" },
        "metadataAddress": { "type": ["string", "null"] },
        "observedSlot": { "type": "integer" }
      }
    },
    "engineVersion": { "type": "string" },
    "raven_version": { "type": "string" },
    "replayHash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
    "officialAttestationHash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
    "keyId": { "type": "string" },
    "issuedAt": { "type": "string", "format": "date-time" },
    "signature": {
      "type": "string",
      "description": "Base64 ed25519 signature over the published canonical preimage recipe. Verify against the key set at the published /pubkey endpoint (see agents.json attestation.publicKeyEndpoint) — the embedded attestationPublicKey is convenience-only and MUST be cross-checked against the published key set, never trusted alone."
    },
    "attestationPublicKey": {
      "type": "string",
      "description": "Convenience copy of the signing public key (base64 SPKI DER). NOT an authority by itself: cross-check keyId against the published /pubkey key set before trusting."
    },
    "signatureAlg": { "const": "ed25519" },
    "served_at": { "type": "string", "format": "date-time" },
    "unsigned": false
  },
  "additionalProperties": true
}
