{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://foray.dunin7.com/schema/foray-transaction-v4_1.schema.json",
  "title": "FORAY Protocol v4.1 Transaction (canonical shape)",
  "$comment": "Canonical conformance artifact for the FORAY v4.1 transaction shape. Derived from the FORAY Protocol v4.1 Specification -- sections 2.1 (top-level template), 2.2 (Required column), 5.3 and 6.2 (settlement and anticipation fields), and 9.5 (attestations) -- as settled by the Canonical Transaction Shape Ruling v0.3 (RULED 2026-07-20). Authority order: the specification text governs everything this schema does not; this schema governs transaction-JSON shape. Every component element (Arrangements included) is wrapped under a foray_core key. Structural shape only -- cross-reference resolution, the allocations-sum-to-amount_settled rule, and the bans on singular _ref fields and extension objects are cross-field/semantic rules enforced by the live validator (POST /api/validate-foray), not expressed here. Revision v0.2, 2026-07-21: provenance comment trimmed to public form; validation behaviour unchanged from foray-transaction-v4_1.schema.json.",
  "type": "object",
  "required": [
    "transaction_id",
    "schema_version",
    "timestamp",
    "foray_core",
    "component_hashes",
    "arrangements",
    "accruals",
    "anticipations",
    "actions",
    "merkle_root",
    "blockchain_anchor"
  ],
  "properties": {
    "transaction_id": { "type": "string" },
    "schema_version": { "const": "4.1" },
    "timestamp": { "type": "string" },
    "foray_core": {
      "type": "object",
      "required": ["entity", "transaction_type", "total_value", "currency"],
      "properties": {
        "entity": { "type": "string" },
        "entity_hash": { "type": "string" },
        "transaction_type": { "type": "string" },
        "total_value": { "type": "number" },
        "currency": { "type": "string" },
        "status": { "type": "string" },
        "compliance_flags": { "type": "array" }
      }
    },
    "component_hashes": { "type": "object" },
    "arrangements": { "type": "array", "items": { "$ref": "#/$defs/Arrangement" } },
    "accruals": { "type": "array", "items": { "$ref": "#/$defs/Accrual" } },
    "anticipations": { "type": "array", "items": { "$ref": "#/$defs/Anticipation" } },
    "actions": { "type": "array", "items": { "$ref": "#/$defs/Action" } },
    "merkle_root": { "type": "string" },
    "blockchain_anchor": { "type": "object" },
    "audit_data_anchor": { "type": "object" },
    "privacy_metadata": { "type": "object" },
    "attestations": {
      "type": "array",
      "$comment": "Optional fifth component type per specification section 9.5. Present for documentation only; its elements are not structurally validated by this schema or by the live validator."
    }
  },
  "$defs": {
    "Arrangement": {
      "type": "object",
      "required": ["id", "foray_core"],
      "properties": {
        "id": { "type": "string" },
        "foray_core": {
          "type": "object",
          "required": ["type", "effective_date", "parties", "terms"],
          "properties": {
            "type": { "type": "string" },
            "effective_date": { "type": "string" },
            "parties": { "type": "array" },
            "terms": { "type": "object" },
            "description": { "type": "string" },
            "total_value": { "type": "number" },
            "currency": { "type": "string" },
            "legal_documentation": { "type": "array" },
            "dependencies": { "type": "array" }
          }
        }
      }
    },
    "Accrual": {
      "type": "object",
      "required": ["id", "foray_core"],
      "properties": {
        "id": { "type": "string" },
        "foray_core": {
          "type": "object",
          "required": ["arrangement_refs"],
          "properties": {
            "arrangement_refs": { "type": "array" }
          }
        }
      }
    },
    "Anticipation": {
      "type": "object",
      "required": ["id", "foray_core"],
      "properties": {
        "id": { "type": "string" },
        "foray_core": {
          "type": "object",
          "required": ["accrual_refs", "arrangement_refs"],
          "$comment": "expected_date and probability_factor are the canonical fields (specification section 6.2) but are deliberately NOT listed as required here -- the live validator enforces them (E4) so it can name the specific wrong-name field (datetime/probability/condition) in the error message rather than emitting a generic structural E3.",
          "properties": {
            "accrual_refs": { "type": "array" },
            "arrangement_refs": { "type": "array" },
            "expected_date": { "type": "string" },
            "probability_factor": { "type": "number" }
          }
        }
      }
    },
    "Action": {
      "type": "object",
      "required": ["id", "foray_core"],
      "properties": {
        "id": { "type": "string" },
        "foray_core": {
          "type": "object",
          "required": ["anticipation_refs", "accrual_refs", "arrangement_refs"],
          "$comment": "amount_settled is the canonical field (specification sections 5.3 and 6.2) but is deliberately NOT listed as required here -- the live validator enforces it (E5) so it can name actual_amount as the specific wrong-name culprit when present, rather than emitting a generic structural E3.",
          "properties": {
            "anticipation_refs": { "type": "array" },
            "accrual_refs": { "type": "array" },
            "arrangement_refs": { "type": "array" },
            "amount_settled": { "type": "number" },
            "allocations": {
              "type": "array",
              "items": { "$ref": "#/$defs/Allocation" }
            }
          }
        }
      }
    },
    "Allocation": {
      "type": "object",
      "required": ["ref", "ref_type", "amount", "currency"],
      "properties": {
        "ref": { "type": "string" },
        "ref_type": { "enum": ["anticipation", "accrual", "arrangement"] },
        "amount": { "type": "number" },
        "currency": { "type": "string" },
        "allocation_type": { "enum": ["full", "partial", "overpayment"] },
        "remaining_balance": { "type": "number" }
      }
    }
  }
}
