{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://mizan.market/verdict/mizan-verdict-1.schema.json",
  "title": "mizan.verdict/1",
  "description": "One signed answer to: may I pay this party under this rule? Fields absent when unknown; never null.",
  "type": "object",
  "required": ["schema", "decision", "subject", "rule", "issued", "expires", "as_of", "request_id", "token", "kid", "status", "details"],
  "additionalProperties": false,
  "properties": {
    "schema": {"const": "mizan.verdict/1"},
    "decision": {"enum": ["ALLOW", "REFUSE"]},
    "subject": {"type": "string", "description": "Canonical id: credential:…, ag:…, evm:…, dns:…, web:…; otherwise the subject as given."},
    "grade": {"enum": ["DECLARED", "RECORDED", "PROVEN"], "description": "Present on ALLOW only; never higher than earned."},
    "met": {"type": "string", "description": "ALLOW only: the bar met, in plain words."},
    "reason": {"type": "string", "description": "REFUSE only: one stable reason code (see reason_codes), or a documented rule-specific code."},
    "measured": {
      "type": "object", "additionalProperties": false,
      "properties": {
        "metric": {"type": "string"},
        "value": {"type": "number"},
        "tries": {"type": "integer", "minimum": 0},
        "counted_before_outcome": {"type": "boolean"}
      },
      "description": "Only earned fields; an unknown field is omitted, never zero."
    },
    "rule": {"type": "object", "required": ["id"], "additionalProperties": false,
             "properties": {"id": {"type": "string"}, "hash": {"type": "string", "pattern": "^sha256:[0-9a-f]{64}$"}}},
    "bound_to": {"type": "object", "required": ["payee", "rule"], "additionalProperties": false,
                 "properties": {"payee": {"type": "string"}, "rule": {"type": "string"},
                                "amount": {"type": "string", "pattern": "^[0-9]+(\\.[0-9]+)? [A-Z0-9]{1,12}$"}}},
    "issued": {"type": "string", "format": "date-time"},
    "expires": {"type": "string", "format": "date-time"},
    "as_of": {"type": "object", "required": ["ledger_size", "head"], "additionalProperties": false,
              "properties": {"ledger_size": {"type": "integer", "minimum": 0}, "head": {"type": "string", "pattern": "^[0-9a-f]{64}$"}}},
    "record": {"type": "object", "required": ["id", "entry", "verify"], "additionalProperties": false,
               "properties": {"id": {"type": "string"}, "entry": {"type": "integer", "minimum": 0}, "verify": {"type": "string", "format": "uri"}}},
    "request_id": {"type": "string"},
    "token": {"type": "string", "pattern": "^mzv1\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$"},
    "kid": {"type": "string"},
    "status": {"type": "string", "format": "uri"},
    "next": {"type": "object", "required": ["proof_request", "what_would_pass"],
             "properties": {"proof_request": {"type": "object"}, "what_would_pass": {"type": "array", "items": {"type": "string"}}}},
    "details": {"type": "string", "format": "uri"}
  },
  "allOf": [
    {"if": {"properties": {"decision": {"const": "ALLOW"}}}, "then": {"required": ["met", "grade"], "not": {"anyOf": [{"required": ["reason"]}, {"required": ["next"]}]}}},
    {"if": {"properties": {"decision": {"const": "REFUSE"}}}, "then": {"required": ["reason", "next"], "not": {"anyOf": [{"required": ["met"]}, {"required": ["grade"]}]}}}
  ],
  "reason_codes": ["no_record", "below_bar", "too_few_tries", "expired", "revoked", "superseded", "rule_unknown", "subject_unresolved", "payee_mismatch"],
  "rule_specific_codes": ["receipt_invalid", "integrity_bundle_hash", "integrity_log_inclusion", "check_unavailable", "rule:<check>"]
}
