{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://globeice.com/schemas/coach-clip.schema.json",
  "title": "GlobeIce Coach Clip Export",
  "description": "Canonical clip payload for exporting coach-reviewed video moments into DOCX/PPTX templates. Semantic validation must also check start_iso < end_iso and apply the human_review publication gates.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "video_id",
    "clip_id",
    "start_iso",
    "end_iso",
    "duration_s",
    "drill_type",
    "intensity_rpe",
    "reps",
    "season_phase",
    "lead_coach",
    "clip_confidence",
    "scene_score",
    "avg_word_confidence",
    "provenance",
    "docx_slot",
    "human_review"
  ],
  "properties": {
    "video_id": {
      "type": "string",
      "minLength": 3,
      "maxLength": 96,
      "pattern": "^[A-Za-z0-9:_-]+$",
      "description": "Stable source video identifier."
    },
    "clip_id": {
      "type": "string",
      "minLength": 3,
      "maxLength": 96,
      "pattern": "^[A-Za-z0-9:_-]+$",
      "description": "Stable clip identifier within the source video."
    },
    "start_iso": {
      "type": "string",
      "format": "date-time",
      "description": "UTC ISO timestamp when the selected clip starts."
    },
    "end_iso": {
      "type": "string",
      "format": "date-time",
      "description": "UTC ISO timestamp when the selected clip ends."
    },
    "duration_s": {
      "type": "number",
      "exclusiveMinimum": 0,
      "maximum": 3600,
      "description": "Clip duration in seconds. Coach-pack auto-publish defaults to 6-240 seconds."
    },
    "drill_type": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "minLength": 2,
        "maxLength": 48,
        "pattern": "^[a-z0-9][a-z0-9-]*$"
      },
      "description": "One or more normalized hockey drill/event tags."
    },
    "intensity_rpe": {
      "type": "integer",
      "minimum": 1,
      "maximum": 10,
      "description": "Coach-estimated intensity on a 1-10 RPE scale."
    },
    "reps": {
      "type": "integer",
      "minimum": 0,
      "maximum": 999,
      "description": "Detected or coach-entered repetitions in the clip."
    },
    "season_phase": {
      "type": "string",
      "enum": ["preseason", "inseason", "playoffs", "offseason", "return_to_play", "development"],
      "description": "Season context used for coach-pack filtering and load interpretation."
    },
    "lead_coach": {
      "type": "string",
      "minLength": 1,
      "maxLength": 96,
      "description": "Display name for the responsible coach or reviewer."
    },
    "clip_confidence": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "description": "Fused confidence that the clip matches GlobeIce coach-pack rules."
    },
    "scene_score": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "description": "Visual scene/shot stability score. Values below 0.30 force human review."
    },
    "avg_word_confidence": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "description": "Average ASR token confidence for the clip transcript. Values below 0.55 force human review."
    },
    "provenance": {
      "type": "object",
      "additionalProperties": false,
      "required": ["channel", "upload_date", "license"],
      "properties": {
        "channel": {
          "type": "string",
          "minLength": 1,
          "maxLength": 96,
          "description": "Camera, feed, or source channel name."
        },
        "upload_date": {
          "type": "string",
          "format": "date",
          "description": "Source upload date in ISO date format."
        },
        "license": {
          "type": "string",
          "enum": ["org-internal", "licensed", "public-link-only", "blocked", "unknown"],
          "description": "Publishing rights classification."
        }
      }
    },
    "docx_slot": {
      "type": "string",
      "minLength": 2,
      "maxLength": 64,
      "pattern": "^[A-Z][A-Z0-9_]{1,63}$",
      "description": "Content-control or bookmark key used by DOCX templates, for example CLIP_A1."
    },
    "svg_path": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4096,
      "description": "Optional SVG path data or artifact pointer for a rink sketch."
    },
    "human_review": {
      "type": "boolean",
      "description": "Must be true when avg_word_confidence < 0.55 or scene_score < 0.30."
    },
    "low_confidence_words": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["token", "t", "conf"],
        "properties": {
          "token": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "t": {
            "type": "number",
            "minimum": 0,
            "description": "Timestamp in seconds from the clip start."
          },
          "conf": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          }
        }
      },
      "default": []
    }
  },
  "$comment": "Auto-publish when clip_confidence >= 0.62, duration_s is inside the configured range, human_review is false, and rights are not blocked/unknown. JSON Schema cannot compare start_iso/end_iso directly, so enforce that in TypeScript."
}
