{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://schemas.verid.com/predicate-envelope/v1.json",
  "title": "Verid Predicate Envelope",
  "description": "The complete set of data the deterministic authorization plane receives. Frozen at v1.0. Tool payloads, customer records, and free text are structurally excluded: every string is a constrained identifier or an enumerated value, and no object in this schema permits additional properties.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_version",
    "agent_id",
    "tool",
    "action",
    "environment",
    "requested_at"
  ],
  "properties": {
    "schema_version": {
      "description": "Frozen. A breaking change requires a new $id and a new major version.",
      "const": "1.0"
    },
    "agent_id": {
      "$ref": "#/$defs/identifier",
      "description": "The acting principal. Opaque identifier, resolved by the tenant directory."
    },
    "tool": {
      "$ref": "#/$defs/identifier",
      "description": "Registered tool key. Must exist in the tenant tool registry."
    },
    "action": {
      "$ref": "#/$defs/identifier",
      "description": "Registered action verb for that tool."
    },
    "environment": {
      "enum": ["development", "staging", "production"]
    },
    "requested_at": {
      "$ref": "#/$defs/timestamp"
    },
    "predicates": {
      "description": "Typed, registered predicates. Every type has documented semantics and exactly one deterministic evaluator. Unregistered types are rejected.",
      "type": "array",
      "maxItems": 64,
      "items": { "$ref": "#/$defs/predicate" }
    }
  },

  "$defs": {
    "identifier": {
      "description": "Opaque identifier. The character class excludes whitespace and punctuation, so an identifier cannot carry prose, an address, or a note.",
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9_.:-]{0,126}[A-Za-z0-9])?$"
    },

    "timestamp": {
      "description": "RFC 3339, UTC, Z suffix, millisecond precision. Local offsets are rejected so canonical form is unambiguous.",
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$"
    },

    "decimal": {
      "description": "Decimal as a string, never a JSON number. IEEE-754 binary floating point cannot represent 0.1 exactly, and a monetary limit that is off by a fraction is a defective control. Scale is preserved verbatim in the canonical form.",
      "type": "string",
      "pattern": "^-?(0|[1-9]\\d{0,17})(\\.\\d{1,6})?$"
    },

    "currency": {
      "description": "ISO 4217 alphabetic code, uppercase.",
      "type": "string",
      "pattern": "^[A-Z]{3}$"
    },

    "predicate": {
      "type": "object",
      "required": ["type"],
      "oneOf": [
        { "$ref": "#/$defs/amountPredicate" },
        { "$ref": "#/$defs/counterpartyReferencePredicate" },
        { "$ref": "#/$defs/dataClassPredicate" },
        { "$ref": "#/$defs/regionPredicate" },
        { "$ref": "#/$defs/recordCountPredicate" },
        { "$ref": "#/$defs/modelProvenancePredicate" }
      ]
    },

    "amountPredicate": {
      "description": "Monetary magnitude. Carries no payer, payee, account, or narrative.",
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "currency", "value"],
      "properties": {
        "type": { "const": "amount" },
        "currency": { "$ref": "#/$defs/currency" },
        "value": { "$ref": "#/$defs/decimal" }
      }
    },

    "counterpartyReferencePredicate": {
      "description": "Reference to a counterparty registered in the tenant directory, or an HMAC of the normalized value under a tenant-held key. Never a name, address, or account number.",
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "value"],
      "properties": {
        "type": { "const": "counterparty_reference" },
        "value": { "$ref": "#/$defs/identifier" },
        "hashed": {
          "description": "True when value is an HMAC rather than a registered reference. Hashing is permitted only for high-entropy identifiers; see the memo, section 3.2.",
          "type": "boolean"
        }
      }
    },

    "dataClassPredicate": {
      "description": "Classification of data the action touches, e.g. pii, phi, pan, internal. Never the data itself.",
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "value"],
      "properties": {
        "type": { "const": "data_class" },
        "value": { "$ref": "#/$defs/identifier" },
        "access": { "enum": ["read", "write", "export"] }
      }
    },

    "regionPredicate": {
      "description": "Destination or residency region for the action.",
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "value"],
      "properties": {
        "type": { "const": "region" },
        "value": {
          "description": "ISO 3166-1 alpha-2, uppercase.",
          "type": "string",
          "pattern": "^[A-Z]{2}$"
        }
      }
    },

    "modelProvenancePredicate": {
      "description": "Which model produced the proposal and whether its weights are under the tenant's control. Added in v1.1 under the additive-only rule (README section 5). Carries model identity and weight integrity only - never the prompt, the completion, the context, or the reasoning.",
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "model", "hosting"],
      "properties": {
        "type": { "const": "model_provenance" },
        "model": {
          "$ref": "#/$defs/identifier",
          "description": "Model identifier. An identifier, so it cannot carry prose."
        },
        "hosting": {
          "description": "Custody of the weights, not the vendor's brand. self_hosted: the tenant controls the weights and the machine. on_device: the end user's own hardware. vendor_hosted: neither.",
          "enum": ["self_hosted", "vendor_hosted", "on_device"]
        },
        "weights_digest": {
          "description": "Lowercase hex SHA-256 over the weights. Optional, because not every runtime can attest one; rejected when malformed, so an unverifiable string cannot pass as an integrity claim.",
          "type": "string",
          "pattern": "^[0-9a-f]{64}$"
        }
      }
    },

    "recordCountPredicate": {
      "description": "Volume of records affected. Supports bulk-export limits without disclosing the records.",
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "value"],
      "properties": {
        "type": { "const": "record_count" },
        "value": { "type": "integer", "minimum": 0, "maximum": 1000000000 }
      }
    }
  }
}
