{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "ValidationReport",
  "description": "Comprehensive validation report",
  "type": "object",
  "required": [
    "critical",
    "errors",
    "info",
    "is_compliant",
    "is_playable",
    "profile",
    "timestamp",
    "warnings"
  ],
  "properties": {
    "critical": {
      "description": "Critical issues that prevent usage",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ValidationIssue"
      }
    },
    "errors": {
      "description": "Errors that must be fixed for compliance",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ValidationIssue"
      }
    },
    "info": {
      "description": "Informational issues",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ValidationIssue"
      }
    },
    "is_compliant": {
      "description": "Whether the package is compliant with base SMPTE standards",
      "type": "boolean"
    },
    "is_playable": {
      "description": "Whether the package is playable despite issues",
      "type": "boolean"
    },
    "profile": {
      "description": "Validation profile used",
      "allOf": [
        {
          "$ref": "#/definitions/ValidationProfile"
        }
      ]
    },
    "suppressed": {
      "description": "Issues that were suppressed by a `RuleSeverity::Off` override. These are not counted toward `is_playable`/`is_compliant` or surfaced by `has_errors`/`summary` — they exist so operators can debug their `RulesConfig` (`--show-suppressed`) without re-running validation. Each carries a `context[\"suppressed_by\"]` annotation naming the rule key that matched.\n\nSkipped during serialisation when empty so reports without suppressed rules keep the previous on-wire shape.",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ValidationIssue"
      }
    },
    "timestamp": {
      "description": "Timestamp of validation",
      "type": "string"
    },
    "warnings": {
      "description": "Warnings that should be addressed",
      "type": "array",
      "items": {
        "$ref": "#/definitions/ValidationIssue"
      }
    }
  },
  "definitions": {
    "Category": {
      "description": "Category of validation issue",
      "oneOf": [
        {
          "description": "XML structure and syntax issues",
          "type": "string",
          "enum": [
            "Structure"
          ]
        },
        {
          "description": "SMPTE schema compliance",
          "type": "string",
          "enum": [
            "Schema"
          ]
        },
        {
          "description": "UUID and reference resolution",
          "type": "string",
          "enum": [
            "Reference"
          ]
        },
        {
          "description": "Asset file availability and integrity",
          "type": "string",
          "enum": [
            "Asset"
          ]
        },
        {
          "description": "Timing, frame rate, and duration issues",
          "type": "string",
          "enum": [
            "Timing"
          ]
        },
        {
          "description": "Codec-level encoding issues (J2K profiles, JPEG-XS, AAC params, PCM bit depth, etc.). For *container*-level concerns (MXF wrapping, partition layout) use `Container`.",
          "type": "string",
          "enum": [
            "Encoding"
          ]
        },
        {
          "description": "MXF / wrapping container constraints — distinct from `Encoding` which covers the codec carried inside the container.",
          "type": "string",
          "enum": [
            "Container"
          ]
        },
        {
          "description": "Audio configuration issues",
          "type": "string",
          "enum": [
            "Audio"
          ]
        },
        {
          "description": "Video configuration issues",
          "type": "string",
          "enum": [
            "Video"
          ]
        },
        {
          "description": "Subtitle and caption issues",
          "type": "string",
          "enum": [
            "Subtitle"
          ]
        },
        {
          "description": "Data essence (ISXD, dynamic metadata sidecars, ancillary data tracks). NOT for *metadata about* essence — that's `Metadata`.",
          "type": "string",
          "enum": [
            "Data"
          ]
        },
        {
          "description": "Metadata and labeling issues",
          "type": "string",
          "enum": [
            "Metadata"
          ]
        },
        {
          "description": "Security and DRM issues",
          "type": "string",
          "enum": [
            "Security"
          ]
        },
        {
          "description": "Studio-specific requirements",
          "type": "object",
          "required": [
            "StudioSpecific"
          ],
          "properties": {
            "StudioSpecific": {
              "type": "string"
            }
          },
          "additionalProperties": false
        }
      ]
    },
    "ImfUuid": {
      "description": "A SMPTE IMF UUID, serialised as a bare UUID string (e.g. \"0eb3d1b9-b77b-4d3f-bbe5-7c69b15dca85\")",
      "type": "string",
      "format": "uuid"
    },
    "IssueSource": {
      "description": "Which authority produced a validation finding.\n\nEncodes the \"prose vs XSD\" provenance distinction that SMPTE ST 2067-3 §5.1 calls out (\"the prose document takes precedence on conflict\"), so callers can filter, group, or apply per-source severity overrides without inspecting the code string.\n\nCurrently *inferred* from the code prefix on a `ValidationIssue` (see `ValidationIssue::source`) — no engine code needs to set it explicitly. If inference ever becomes ambiguous (e.g. a non-XSD engine internal rule that wants the `XSD/` prefix for catalogue reasons), we can add a `with_source()` builder without changing the public shape.",
      "oneOf": [
        {
          "description": "Came from the runtime XSD validator (uppsala). Schema-layer: the structural subset of the spec that the XSD DSL can express.",
          "type": "string",
          "enum": [
            "XsdLayer"
          ]
        },
        {
          "description": "Came from a hand-rolled prose-cited rule. Semantic/cross-field/ value-set checks that XSD can't express; the rule's code typically cites a SMPTE prose section (e.g. `ST2067-2:2020:6.4.2`).",
          "type": "string",
          "enum": [
            "ProseRule"
          ]
        },
        {
          "description": "Came from imferno engine internals — parse failures, package structure checks, manifest issues — not directly traceable to a single SMPTE spec section.",
          "type": "string",
          "enum": [
            "EngineInternal"
          ]
        }
      ]
    },
    "Location": {
      "description": "Location where the issue was found",
      "type": "object",
      "properties": {
        "cpl_filename": {
          "description": "CPL filename if applicable",
          "type": [
            "string",
            "null"
          ]
        },
        "cpl_id": {
          "description": "CPL UUID if applicable",
          "anyOf": [
            {
              "$ref": "#/definitions/ImfUuid"
            },
            {
              "type": "null"
            }
          ]
        },
        "cpl_title": {
          "description": "CPL content title if applicable",
          "type": [
            "string",
            "null"
          ]
        },
        "file": {
          "description": "File path if applicable",
          "type": [
            "string",
            "null"
          ]
        },
        "line": {
          "description": "Line number in XML file",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint",
          "minimum": 0.0
        },
        "path": {
          "description": "XPath or field path",
          "type": [
            "string",
            "null"
          ]
        },
        "resource_id": {
          "description": "Resource UUID if applicable",
          "type": [
            "string",
            "null"
          ]
        },
        "segment": {
          "description": "Segment index (0-based)",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint",
          "minimum": 0.0
        },
        "sequence_id": {
          "description": "Sequence UUID if applicable",
          "type": [
            "string",
            "null"
          ]
        },
        "timecode": {
          "description": "Timecode if applicable",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "Severity": {
      "description": "Severity level of validation issues",
      "oneOf": [
        {
          "description": "Informational - Best practice suggestions",
          "type": "string",
          "enum": [
            "Info"
          ]
        },
        {
          "description": "Warning - Should fix but not critical",
          "type": "string",
          "enum": [
            "Warning"
          ]
        },
        {
          "description": "Error - Must fix for compliance",
          "type": "string",
          "enum": [
            "Error"
          ]
        },
        {
          "description": "Critical - Prevents package from being usable",
          "type": "string",
          "enum": [
            "Critical"
          ]
        }
      ]
    },
    "ValidationIssue": {
      "description": "A single validation issue",
      "type": "object",
      "required": [
        "category",
        "code",
        "context",
        "location",
        "message",
        "severity"
      ],
      "properties": {
        "additional_instances": {
          "description": "Other `Location`s when this issue represents an aggregation of multiple identical-code occurrences (see [`ValidationReport::aggregate`]). Empty for fresh, un-aggregated issues. Skipped during serialisation when empty so the on-wire shape stays back-compatible for callers that don't aggregate.",
          "type": "array",
          "items": {
            "$ref": "#/definitions/Location"
          }
        },
        "category": {
          "description": "Category of issue",
          "allOf": [
            {
              "$ref": "#/definitions/Category"
            }
          ]
        },
        "code": {
          "description": "Error code (e.g., \"ST2067-2:2020:8.3/FileNotFound\")",
          "type": "string"
        },
        "context": {
          "description": "Additional context",
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        "location": {
          "description": "Location where issue was found",
          "allOf": [
            {
              "$ref": "#/definitions/Location"
            }
          ]
        },
        "message": {
          "description": "Human-readable message",
          "type": "string"
        },
        "severity": {
          "description": "Severity level",
          "allOf": [
            {
              "$ref": "#/definitions/Severity"
            }
          ]
        },
        "source": {
          "description": "Authority that emitted this issue (XSD layer, prose rule, engine internal). Inferred from `code` at construction time so the field is always consistent with the code prefix — JS consumers can filter on `issue.source` directly without re-implementing the inference. Deserialised with a default so old reports without the field round-trip cleanly.",
          "default": "EngineInternal",
          "allOf": [
            {
              "$ref": "#/definitions/IssueSource"
            }
          ]
        },
        "suggestion": {
          "description": "Suggestion for how to fix",
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "ValidationProfile": {
      "description": "Validation profile determining strictness",
      "oneOf": [
        {
          "description": "Minimal validation - just check if playable",
          "type": "string",
          "enum": [
            "Minimal"
          ]
        },
        {
          "description": "Standard SMPTE compliance",
          "type": "string",
          "enum": [
            "SMPTE"
          ]
        },
        {
          "description": "Custom profile with specific rules",
          "type": "string",
          "enum": [
            "Custom"
          ]
        }
      ]
    }
  }
}