{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://paloframework.org/schemas/palo-agentic-effect-contract.schema.json",
  "title": "PALO Agentic Effect Contract",
  "description": "Developer-preview contract describing observable preconditions, intended effects and forbidden effects for a governed action.",
  "type": "object",
  "required": ["format", "schemaVersion", "effectContractId", "resourceSelector", "preconditions", "expectedEffects", "forbiddenEffects", "verification"],
  "properties": {
    "format": { "const": "palo-agentic-effect-contract" },
    "schemaVersion": { "enum": ["1.0.0", "1.1.0"] },
    "effectContractId": { "type": "string", "pattern": "^effect-[a-f0-9-]{36}$" },
    "resourceSelector": {
      "type": "object",
      "required": ["resource", "path"],
      "properties": {
        "resource": { "type": "string", "minLength": 1, "maxLength": 1000 },
        "path": { "type": "string", "minLength": 1, "maxLength": 1000, "pattern": "^/" },
        "tenantId": { "type": "string", "minLength": 1, "maxLength": 128 }
      },
      "additionalProperties": false
    },
    "preconditions": { "$ref": "#/$defs/predicateList" },
    "expectedEffects": { "$ref": "#/$defs/predicateList" },
    "forbiddenEffects": { "$ref": "#/$defs/predicateList" },
    "verification": {
      "type": "object",
      "required": ["windowSeconds", "onInconclusive"],
      "properties": {
        "windowSeconds": { "type": "integer", "minimum": 1, "maximum": 86400 },
        "onInconclusive": { "enum": ["hold_and_review", "retry_then_review"] },
        "maxAttempts": { "type": "integer", "minimum": 1, "maximum": 10 },
        "initialDelaySeconds": { "type": "integer", "minimum": 0, "maximum": 86400 },
        "retryBackoffSeconds": { "type": "integer", "minimum": 1, "maximum": 86400 }
      },
      "additionalProperties": false
    },
    "recovery": {
      "type": "object",
      "required": ["onMismatch"],
      "properties": {
        "onMismatch": { "enum": ["hold_and_review", "propose_compensation"] },
        "compensationAction": {
          "type": "object",
          "required": ["tool", "operation", "resource", "path"],
          "properties": {
            "tool": { "type": "string", "minLength": 1, "maxLength": 200 },
            "operation": { "enum": ["create", "update", "delete", "execute"] },
            "resource": { "type": "string", "minLength": 1, "maxLength": 1000 },
            "path": { "type": "string", "minLength": 1, "maxLength": 1000, "pattern": "^/" }
          },
          "additionalProperties": false
        }
      },
      "allOf": [
        {
          "if": { "properties": { "onMismatch": { "const": "propose_compensation" } }, "required": ["onMismatch"] },
          "then": { "properties": { "compensationAction": { "type": "object" } }, "required": ["compensationAction"] }
        }
      ],
      "additionalProperties": false
    }
  },
  "allOf": [
    {
      "if": { "properties": { "schemaVersion": { "const": "1.0.0" } }, "required": ["schemaVersion"] },
      "then": {
        "properties": {
          "preconditions": { "$ref": "#/$defs/legacyPredicateList" },
          "expectedEffects": { "$ref": "#/$defs/legacyPredicateList" },
          "forbiddenEffects": { "$ref": "#/$defs/legacyPredicateList" },
          "verification": { "type": "object", "properties": { "initialDelaySeconds": false, "retryBackoffSeconds": false } },
          "recovery": false
        }
      }
    }
  ],
  "$defs": {
    "legacyPredicateList": {
      "type": "array",
      "items": {
        "allOf": [
          { "$ref": "#/$defs/predicate" },
          { "type": "object", "properties": { "operator": { "enum": ["exists", "equals", "unchanged", "changedTo", "deltaWithin"] } } }
        ]
      }
    },
    "predicateList": {
      "type": "array",
      "maxItems": 100,
      "items": { "$ref": "#/$defs/predicate" }
    },
    "predicate": {
      "type": "object",
      "required": ["predicateId", "path", "operator"],
      "properties": {
        "predicateId": { "type": "string", "pattern": "^predicate-[a-zA-Z0-9._-]{1,100}$" },
        "path": { "type": "string", "pattern": "^(|/(?:[^~/]|~0|~1)*)$", "maxLength": 1000 },
        "operator": { "enum": ["exists", "notExists", "equals", "unchanged", "changedTo", "deltaWithin", "numberWithin", "containsAll", "typeIs"] },
        "value": true,
        "minimumDelta": { "type": "number" },
        "maximumDelta": { "type": "number" },
        "minimum": { "type": "number" },
        "maximum": { "type": "number" },
        "values": { "type": "array", "uniqueItems": true, "maxItems": 100, "items": true },
        "expectedType": { "enum": ["array", "boolean", "null", "number", "object", "string"] },
        "description": { "type": "string", "maxLength": 500 }
      },
      "allOf": [
        {
          "if": { "properties": { "operator": { "enum": ["equals", "changedTo"] } }, "required": ["operator"] },
          "then": { "properties": { "value": true }, "required": ["value"] }
        },
        {
          "if": { "properties": { "operator": { "const": "deltaWithin" } }, "required": ["operator"] },
          "then": { "properties": { "minimumDelta": { "type": "number" }, "maximumDelta": { "type": "number" } }, "required": ["minimumDelta", "maximumDelta"] }
        },
        {
          "if": { "properties": { "operator": { "const": "numberWithin" } }, "required": ["operator"] },
          "then": { "properties": { "minimum": { "type": "number" }, "maximum": { "type": "number" } }, "required": ["minimum", "maximum"] }
        },
        {
          "if": { "properties": { "operator": { "const": "containsAll" } }, "required": ["operator"] },
          "then": { "properties": { "values": { "type": "array" } }, "required": ["values"] }
        },
        {
          "if": { "properties": { "operator": { "const": "typeIs" } }, "required": ["operator"] },
          "then": { "properties": { "expectedType": { "type": "string" } }, "required": ["expectedType"] }
        }
      ],
      "additionalProperties": false
    }
  },
  "additionalProperties": false
}
