{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://alxprotocol.com/protocol/1/schemas/attribution-trace.schema.json",
  "title": "ALX Attribution Trace",
  "description": "Complete deterministic derivation structure computed from a root Block. An AttributionTrace is not a Block, has no protocol-defined identity, and is not a paginated graph-query envelope.",
  "$comment": "This schema validates structural shape only. Conformant Trace computation additionally requires the root to be present in the supplied Graph and represented in nodes, and requires relational verification of edges, leaves, depths, pathCount, and graph consistency. Partial, paginated, and truncated service responses do not conform to this schema.",
  "type": "object",
  "properties": {
    "root": {
      "$ref": "./defs.schema.json#/$defs/hash",
      "description": "blockHash of the root Block whose lineage was traced. Conformant computation requires this Block to be present in the supplied Graph and represented in nodes."
    },
    "validationMode": {
      "enum": ["closed-world", "open-world"],
      "description": "Validation mode used during the trace: closed-world requires all parentHashes to resolve; open-world permits declared external boundaries."
    },
    "complete": {
      "type": "boolean",
      "description": "True only when all required lineage was resolved under the selected validation mode."
    },
    "nodes": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "type": "object",
        "properties": {
          "hash": {
            "$ref": "./defs.schema.json#/$defs/hash"
          },
          "minDepth": {
            "type": "integer",
            "minimum": 0,
            "description": "Shortest path length from root to this node"
          },
          "maxDepth": {
            "type": "integer",
            "minimum": 0,
            "description": "Longest path length from root to this node"
          },
          "pathCount": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$",
            "description": "Exact number of distinct paths from root to this node, encoded as a canonical base-10 decimal string"
          },
          "parentCount": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of direct parents this node has"
          },
          "childCount": {
            "type": "integer",
            "minimum": 0,
            "description": "Trace-local reverse degree: the number of returned edges whose to value equals this node's hash. Blocks outside the returned Trace are excluded."
          }
        },
        "required": ["hash", "minDepth", "maxDepth", "pathCount", "parentCount", "childCount"],
        "additionalProperties": false
      }
    },
    "edges": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "type": "object",
        "properties": {
          "from": {
            "$ref": "./defs.schema.json#/$defs/hash",
            "description": "Child block hash"
          },
          "to": {
            "$ref": "./defs.schema.json#/$defs/hash",
            "description": "Parent block hash"
          }
        },
        "required": ["from", "to"],
        "additionalProperties": false
      }
    },
    "leaves": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "$ref": "./defs.schema.json#/$defs/hash"
      },
      "description": "Resolved nodes with no resolved parents. External parents are not leaves unless they are resolved as nodes."
    },
    "missingParents": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "$ref": "./defs.schema.json#/$defs/hash"
      },
      "description": "Unresolved parent hashes that were not declared as external boundaries."
    },
    "externalParents": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "$ref": "./defs.schema.json#/$defs/hash"
      },
      "description": "Unresolved parent hashes explicitly declared as external boundaries in verification context."
    },
    "maxDepth": {
      "type": "integer",
      "minimum": 0,
      "description": "Longest path length from the root Block to any node in the trace."
    }
  },
  "required": ["root", "validationMode", "complete", "nodes", "edges", "leaves", "missingParents", "externalParents", "maxDepth"],
  "additionalProperties": false,
  "allOf": [
    {
      "if": {
        "properties": {
          "validationMode": { "const": "closed-world" }
        },
        "required": ["validationMode"]
      },
      "then": {
        "properties": {
          "externalParents": { "maxItems": 0 }
        }
      }
    },
    {
      "if": {
        "properties": {
          "externalParents": { "minItems": 1 }
        },
        "required": ["externalParents"]
      },
      "then": {
        "properties": {
          "complete": { "const": false }
        }
      }
    }
  ]
}
