{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/agenticrail-nz/json-schema/agenticrail-nz-evaluate-response-schema.json",
  "title": "EvaluateResponse",
  "x-generated": "2026-11-01",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/agenticrail-nz-openapi.json#/components/schemas/EvaluateResponse",
  "type": "object",
  "properties": {
    "decision": {
      "type": "string",
      "enum": [
        "ALLOW",
        "DENY"
      ],
      "description": "The enforcement decision. `HALT` is a status, not a decision: a halted request is refused at the boundary before enforcement and therefore produces no receipt."
    },
    "lane": {
      "type": "string",
      "enum": [
        "public-demo"
      ],
      "description": "Present ONLY when the caller was moved to the public demo lane because the credential presented was not recognised. Absent on an authenticated call, and absent when the demo key was presented deliberately -- so its presence always means this is not the lane the caller asked for."
    },
    "lane_reason": {
      "type": "string",
      "enum": [
        "no_key_supplied",
        "key_format_invalid",
        "key_not_registered"
      ],
      "description": "Why the caller landed on the demo lane."
    },
    "lane_notice": {
      "type": "string",
      "description": "Human-readable notice: the sequence is `demo-` prefixed and its report can be read by anyone with the sequence id."
    },
    "execution_submitted": {
      "type": "boolean",
      "description": "Whether the executor was handed the step. This is the EXECUTOR outcome and is NOT signed into the receipt. Do not confuse it with the receipt's `executed` field, which means only that the decision was ALLOW."
    },
    "sealed": {
      "type": "boolean",
      "enum": [
        true
      ],
      "description": "Present ONLY on the ALLOW that closes the sequence, i.e. the final step of its declared order. Never sent on a DENY or on an intermediate step, so its absence means the sequence is still open. Once sealed, any further call on the same sequence_id is refused with `SEALED_SEQUENCE`. A sealed sequence is the finished record: it can be read whole from the report, which shows `seal_status: SEALED`."
    },
    "seal_notice": {
      "type": "string",
      "description": "Human-readable notice sent with `sealed: true`: the sequence is closed, and where to read its report."
    },
    "pack_id": {
      "type": "string",
      "description": "This decision's receipt identifier (sha256)."
    },
    "reasons": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/DenialCode"
      },
      "description": "Empty on ALLOW. On DENY, every rule that refused the step; phase-1 checks can report more than one at once."
    },
    "sequence_id": {
      "type": "string"
    },
    "step": {
      "type": "string"
    },
    "function": {
      "type": "string"
    },
    "action_type": {
      "type": "string"
    },
    "model_id": {
      "type": "string",
      "description": "Always `client:<your-client-id>`."
    },
    "result": {
      "type": "object",
      "description": "Executor outcome detail. `status` is `submitted` on ALLOW, `skipped` on DENY.",
      "additionalProperties": true
    },
    "receipt": {
      "$ref": "#/$defs/ReceiptMetadata"
    },
    "log": {
      "type": "object",
      "properties": {
        "ok": {
          "type": "boolean"
        },
        "error": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "allowed_action_types": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "DENY with `ACTION_NOT_ALLOWED` only: the action types this step would have accepted. Not signed."
    },
    "next_expected_step": {
      "type": "string",
      "description": "DENY with `SEQUENCE_VIOLATION` only: the step the sequence is waiting for. Not signed."
    },
    "locked_step_order": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "DENY with `STEP_ORDER_MISMATCH` only: the order this sequence was locked to on its first call. Resend this list. Not signed."
    },
    "expected_step_order": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "DENY with `UNKNOWN_STEP` only: the step order the step had to appear in. Not signed."
    },
    "step_order_source": {
      "type": "string",
      "enum": [
        "caller",
        "msmd_spine"
      ],
      "description": "With `expected_step_order`: whether that order was the caller's `step_order` or the built-in MSMD spine (used when `step_order` was absent). Not signed."
    },
    "sequence_scope_notice": {
      "type": "string",
      "description": "Present when the sequence was scoped differently from what the caller may expect. Not signed."
    }
  },
  "$defs": {
    "DenialCode": {
      "type": "string",
      "description": "Why a step was refused.",
      "enum": [
        "UNKNOWN_STEP",
        "ACTION_NOT_ALLOWED",
        "FUNCTION_STEP_MISMATCH",
        "SEALED_SEQUENCE",
        "REPLAY_NONCE",
        "SEQUENCE_VIOLATION",
        "STALE_TIMESTAMP",
        "ARTIFACT_UNBOUND",
        "STEP_ORDER_MISMATCH"
      ]
    },
    "ReceiptMetadata": {
      "type": "object",
      "description": "Signature METADATA only. The raw signature is deliberately never echoed here — retrieve it, with its `signed_canonical` preimage, from `POST /v1/report`. Two surfaces on purpose: the synchronous path stays lean, the report is the evidence.",
      "properties": {
        "pack_id": {
          "type": "string"
        },
        "key_id": {
          "type": "string",
          "description": "Selects the verification key. Active: `k2_2026-06-07_ed25519`."
        },
        "signature": {
          "type": "null",
          "description": "Always null here by design. See the description of this schema."
        },
        "signature_alg": {
          "type": "string",
          "enum": [
            "Ed25519",
            "HMAC-SHA256"
          ]
        },
        "payload_hash": {
          "type": "string"
        },
        "prev_receipt_id": {
          "type": [
            "string",
            "null"
          ],
          "description": "Anchor: the `pack_id` of the last ALLOWED receipt. Null before the first ALLOW in a sequence, which is legitimate — a denied opening step and the retry after it both carry null. Chain verification resolves predecessors by this anchor, never by position."
        },
        "prev_receipt_hash": {
          "type": [
            "string",
            "null"
          ],
          "description": "sha256 of the predecessor's full canonical JSON, signature included. An identifier reference and a content hash are different things; this is the content hash."
        },
        "decision_index": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1,
          "description": "This decision's position among every decision in the sequence, counted from 1 across ALLOW and DENY alike, and signed into the receipt (added 2026-10-08). The prev_receipt chain runs through ALLOWED receipts only, so nothing links to a DENY; the numbering is what makes a removed receipt of either decision visible as a missing number. Keep it with your own copy of each response and you can name a missing receipt without reading ours. Null if the number could not be reserved."
        },
        "ts_ms": {
          "type": "integer"
        },
        "version": {
          "type": "string",
          "enum": [
            "slp8_receipt_v2",
            "slp8_receipt_v3"
          ]
        },
        "attestation": {
          "type": [
            "object",
            "null"
          ],
          "additionalProperties": true
        }
      }
    }
  }
}