{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "th.schema.json",
  "title": "Per-clip talking-head annotation (dataset 3, merged)",
  "description": "Talking-head record contract. clip_id, language and duration are required; other fields are nullable — partial records are valid.",
  "type": "object",
  "required": [
    "clip_id",
    "clip_path",
    "language",
    "duration",
    "transform_version"
  ],
  "properties": {
    "clip_id": {
      "type": "string",
      "minLength": 1
    },
    "clip_path": {
      "type": "string",
      "minLength": 1
    },
    "source_url": {
      "type": [
        "string",
        "null"
      ]
    },
    "channel": {
      "type": [
        "string",
        "null"
      ]
    },
    "yt_license": {
      "type": [
        "string",
        "null"
      ]
    },
    "seed_query": {
      "type": [
        "string",
        "null"
      ]
    },
    "language": {
      "type": [
        "string",
        "null"
      ]
    },
    "language_detected": {
      "type": [
        "string",
        "null"
      ]
    },
    "language_probability": {
      "type": [
        "number",
        "null"
      ]
    },
    "duration": {
      "type": [
        "number",
        "null"
      ],
      "exclusiveMinimum": 0
    },
    "resolution": {
      "type": [
        "array",
        "null"
      ],
      "prefixItems": [
        {
          "type": "integer"
        },
        {
          "type": "integer"
        }
      ],
      "minItems": 2,
      "maxItems": 2
    },
    "fps": {
      "type": [
        "number",
        "null"
      ]
    },
    "speaker_turns": {
      "type": "array",
      "description": "Active-speaker turns: [{start, end, track_id, score_mean}]; a legacy [start, end] pair is also accepted.",
      "items": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "start": {
                "type": "number"
              },
              "end": {
                "type": "number"
              },
              "track_id": {
                "type": "integer"
              },
              "score_mean": {
                "type": "number"
              }
            },
            "required": [
              "start",
              "end",
              "track_id"
            ]
          },
          {
            "type": "array",
            "prefixItems": [
              {
                "type": "number"
              },
              {
                "type": "number"
              }
            ],
            "minItems": 2,
            "maxItems": 2
          }
        ]
      }
    },
    "active_track_id": {
      "type": [
        "integer",
        "null"
      ]
    },
    "speaking_frac": {
      "type": [
        "number",
        "null"
      ]
    },
    "asd_confidence": {
      "type": [
        "number",
        "null"
      ]
    },
    "is_speaker_visible": {
      "type": [
        "boolean",
        "null"
      ]
    },
    "n_tracks": {
      "type": [
        "integer",
        "null"
      ]
    },
    "face_bbox_track": {
      "type": "array",
      "items": {
        "type": "array",
        "prefixItems": [
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          }
        ],
        "minItems": 5,
        "maxItems": 5
      }
    },
    "tracks": {
      "type": "array",
      "description": "Identity-stable face tracks (IoU association). boxes are [[t_ms, x, y, w, h], ...] in the same downscaled frame space as face_bbox_track, with t in milliseconds. Viewers should render only the active track (active_track_id) by default; records without tracks fall back to face_bbox_track.",
      "items": {
        "type": "object",
        "properties": {
          "track_id": {
            "type": "integer"
          },
          "start_ms": {
            "type": "integer"
          },
          "end_ms": {
            "type": "integer"
          },
          "n_boxes": {
            "type": "integer"
          },
          "boxes": {
            "type": "array",
            "items": {
              "type": "array",
              "prefixItems": [
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                },
                {
                  "type": "number"
                }
              ],
              "minItems": 5,
              "maxItems": 5
            }
          }
        },
        "required": [
          "track_id",
          "start_ms",
          "end_ms",
          "boxes"
        ]
      }
    },
    "landmarks_npz": {
      "type": [
        "string",
        "null"
      ]
    },
    "asr_text": {
      "type": [
        "string",
        "null"
      ]
    },
    "asr_word_ts": {
      "type": "array",
      "items": {
        "type": "array",
        "prefixItems": [
          {
            "type": "string"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          }
        ],
        "minItems": 3,
        "maxItems": 3
      }
    },
    "phoneme_viseme_timeline": {
      "type": "array",
      "items": {
        "type": "array",
        "prefixItems": [
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "string"
          },
          {
            "type": "string"
          }
        ],
        "minItems": 4,
        "maxItems": 4
      }
    },
    "viseme_set": {
      "type": [
        "string",
        "null"
      ]
    },
    "viseme_backend": {
      "type": [
        "string",
        "null"
      ],
      "description": "Viseme alignment backend: 'mfa' (multilingual forced alignment, IPA to viseme classes) | 'approx' (grapheme-based approximation) | 'none' (no audio/text)."
    },
    "emotion_label": {
      "type": [
        "string",
        "null"
      ]
    },
    "emotion_intensity": {
      "type": [
        "number",
        "null"
      ],
      "minimum": 0,
      "maximum": 1
    },
    "av_sync_score": {
      "type": [
        "number",
        "null"
      ]
    },
    "av_sync_conf": {
      "type": [
        "number",
        "null"
      ]
    },
    "av_offset": {
      "type": [
        "number",
        "null"
      ]
    },
    "av_offset_ms": {
      "type": [
        "number",
        "null"
      ]
    },
    "head_pose": {
      "type": "array",
      "items": {
        "type": "array",
        "prefixItems": [
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          },
          {
            "type": "number"
          }
        ],
        "minItems": 4,
        "maxItems": 4
      }
    },
    "is_public_figure": {
      "type": [
        "boolean",
        "null"
      ]
    },
    "quality_ok": {
      "type": [
        "boolean",
        "null"
      ]
    },
    "gates": {
      "type": [
        "object",
        "null"
      ],
      "description": "Quality-gate cascade: per-gate values and verdicts are stored for auditability.",
      "properties": {
        "authentic": {
          "type": "object",
          "properties": {
            "method": {
              "type": "string"
            },
            "flag": {
              "type": "boolean"
            }
          }
        },
        "language": {
          "type": "object",
          "properties": {
            "expected": {
              "type": [
                "string",
                "null"
              ]
            },
            "detected": {
              "type": [
                "string",
                "null"
              ]
            },
            "prob": {
              "type": [
                "number",
                "null"
              ]
            },
            "ok": {
              "type": "boolean"
            }
          }
        },
        "geometry": {
          "type": "object",
          "properties": {
            "yaw_med": {
              "type": [
                "number",
                "null"
              ]
            },
            "pitch_med": {
              "type": [
                "number",
                "null"
              ]
            },
            "roll_med": {
              "type": [
                "number",
                "null"
              ]
            },
            "face_h_frac": {
              "type": [
                "number",
                "null"
              ]
            },
            "face_h_px_med": {
              "type": [
                "number",
                "null"
              ]
            },
            "frontal_frac": {
              "type": [
                "number",
                "null"
              ]
            },
            "ok": {
              "type": "boolean"
            }
          }
        },
        "resolution": {
          "type": "object",
          "description": "Source height meets the minimum resolution bar (1080p); a manual waiver is possible for scarce languages.",
          "properties": {
            "src_h": {
              "type": [
                "integer",
                "null"
              ]
            },
            "ok": {
              "type": "boolean"
            },
            "waiver": {
              "type": "boolean"
            }
          }
        },
        "audio": {
          "type": "object",
          "properties": {
            "snr_db": {
              "type": [
                "number",
                "null"
              ]
            },
            "speech_frac": {
              "type": [
                "number",
                "null"
              ]
            },
            "music_frac": {
              "type": [
                "number",
                "null"
              ]
            },
            "singing_frac": {
              "type": [
                "number",
                "null"
              ]
            },
            "ok": {
              "type": "boolean"
            }
          }
        },
        "speaking": {
          "type": "object",
          "properties": {
            "speaking_frac": {
              "type": [
                "number",
                "null"
              ]
            },
            "asd_confidence": {
              "type": [
                "number",
                "null"
              ]
            },
            "ok": {
              "type": "boolean"
            }
          }
        },
        "sync": {
          "type": "object",
          "properties": {
            "offset_ms": {
              "type": [
                "number",
                "null"
              ]
            },
            "conf": {
              "type": [
                "number",
                "null"
              ]
            },
            "ok": {
              "type": "boolean"
            }
          }
        }
      }
    },
    "resolution_ok": {
      "type": [
        "boolean",
        "null"
      ]
    },
    "single_speaker": {
      "type": [
        "boolean",
        "null"
      ]
    },
    "watermark_id": {
      "type": [
        "string",
        "null"
      ]
    },
    "fetched_at": {
      "type": [
        "string",
        "null"
      ]
    },
    "transform_version": {
      "type": "string",
      "minLength": 1
    },
    "transform_hash": {
      "type": [
        "string",
        "null"
      ]
    }
  }
}