{
  "version": "1.0.0",
  "method": {
    "title": "Twenty original subtitle edge cases",
    "scope": "Synthetic text fixtures for a limited structural and editorial checker; not complete SRT or WebVTT conformance or player compatibility testing.",
    "webvttSource": "https://www.w3.org/TR/2026/CRD-webvtt1-20260520/",
    "checked": "2026-09-14",
    "srtPolicy": "Local delivery policy: numeric identifiers, blank-separated cues, HH:MM:SS,mmm timestamps with minute/second ranges 00–59, positive durations and nonempty visible text. This is not specified by WebVTT.",
    "thresholds": {
      "maxCps": 20,
      "maxLine": 42
    }
  },
  "cases": [
    {
      "id": "srt-clean",
      "title": "SRT clean control",
      "format": "SRT",
      "purpose": "Establish a small readable numeric cue.",
      "file": "subtitle-corpus-srt-clean.srt",
      "input": "1\n00:00:01,000 --> 00:00:04,000\nMap the room.\n",
      "structuralFindings": [],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 0,
        "warnings": 0
      },
      "explanation": "Establish a small readable numeric cue."
    },
    {
      "id": "srt-unicode",
      "title": "SRT multilingual text",
      "format": "SRT",
      "purpose": "Preserve original UTF-8 accents, CJK and emoji.",
      "file": "subtitle-corpus-srt-unicode.srt",
      "input": "1\n00:00:01,000 --> 00:00:06,000\nCafé — 東京 🌍\n",
      "structuralFindings": [],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 0,
        "warnings": 0
      },
      "explanation": "Preserve original UTF-8 accents, CJK and emoji."
    },
    {
      "id": "srt-dot",
      "title": "SRT decimal separator",
      "format": "SRT",
      "purpose": "Reject periods under this corpus's comma-based SRT policy.",
      "file": "subtitle-corpus-srt-dot.srt",
      "input": "1\n00:00:01.000 --> 00:00:04.000\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "invalid-timestamp-srt",
          "message": "Invalid SRT timestamp; check separators and minute/second ranges."
        },
        {
          "cue": "",
          "code": "no-readable-cues",
          "message": "No readable timed cues found."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 0,
        "errors": 2,
        "warnings": 0
      },
      "explanation": "Reject periods under this corpus's comma-based SRT policy."
    },
    {
      "id": "srt-range",
      "title": "SRT minute range",
      "format": "SRT",
      "purpose": "Reject a minute component of 60.",
      "file": "subtitle-corpus-srt-range.srt",
      "input": "1\n00:60:01,000 --> 00:60:04,000\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "invalid-timestamp-srt",
          "message": "Invalid SRT timestamp; check separators and minute/second ranges."
        },
        {
          "cue": "",
          "code": "no-readable-cues",
          "message": "No readable timed cues found."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 0,
        "errors": 2,
        "warnings": 0
      },
      "explanation": "Reject a minute component of 60."
    },
    {
      "id": "srt-missing-end",
      "title": "SRT missing end timestamp",
      "format": "SRT",
      "purpose": "Require a complete timing line.",
      "file": "subtitle-corpus-srt-missing-end.srt",
      "input": "1\n00:00:01,000 -->\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "malformed-timing",
          "message": "Missing or malformed timing line."
        },
        {
          "cue": "",
          "code": "no-readable-cues",
          "message": "No readable timed cues found."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 0,
        "errors": 2,
        "warnings": 0
      },
      "explanation": "Require a complete timing line."
    },
    {
      "id": "srt-reversed",
      "title": "SRT reversed duration",
      "format": "SRT",
      "purpose": "Reject an ending before the start.",
      "file": "subtitle-corpus-srt-reversed.srt",
      "input": "1\n00:00:04,000 --> 00:00:01,000\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "invalid-duration",
          "message": "End time must be later than start time."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 1,
        "warnings": 0
      },
      "explanation": "Reject an ending before the start."
    },
    {
      "id": "srt-empty",
      "title": "SRT empty caption",
      "format": "SRT",
      "purpose": "Flag missing caption text under the local delivery policy.",
      "file": "subtitle-corpus-srt-empty.srt",
      "input": "1\n00:00:01,000 --> 00:00:04,000\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "empty-text",
          "message": "Cue text is empty."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 1,
        "warnings": 0
      },
      "explanation": "Flag missing caption text under the local delivery policy."
    },
    {
      "id": "srt-overlap",
      "title": "SRT intentional overlap",
      "format": "SRT",
      "purpose": "Prompt editorial review of two simultaneous voices.",
      "file": "subtitle-corpus-srt-overlap.srt",
      "input": "1\n00:00:01,000 --> 00:00:05,000\nLeft.\n\n2\n00:00:02,000 --> 00:00:04,000\nRight.\n",
      "structuralFindings": [],
      "editorialWarnings": [
        {
          "cue": 2,
          "code": "overlap",
          "message": "Cue overlaps an earlier cue; confirm whether simultaneous captions are intentional."
        }
      ],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 2,
        "errors": 0,
        "warnings": 1
      },
      "explanation": "Both intervals are well formed. Simultaneous captions can be intentional; inspect the intended player."
    },
    {
      "id": "srt-missing-separator",
      "title": "SRT missing blank separator",
      "format": "SRT",
      "purpose": "Detect a second timing line swallowed into caption text.",
      "file": "subtitle-corpus-srt-missing-separator.srt",
      "input": "1\n00:00:01,000 --> 00:00:10,000\nOne.\n2\n00:00:05,000 --> 00:00:06,000\nTwo.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "missing-separator",
          "message": "Another timing line occurs inside cue text; check for a missing blank line between cues."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 1,
        "warnings": 0
      },
      "explanation": "Detect a second timing line swallowed into caption text."
    },
    {
      "id": "srt-zero-duration",
      "title": "SRT zero duration",
      "format": "SRT",
      "purpose": "Require positive duration.",
      "file": "subtitle-corpus-srt-zero-duration.srt",
      "input": "1\n00:00:01,000 --> 00:00:01,000\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "invalid-duration",
          "message": "End time must be later than start time."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 1,
        "warnings": 0
      },
      "explanation": "Require positive duration."
    },
    {
      "id": "vtt-clean",
      "title": "WebVTT clean control",
      "format": "VTT",
      "purpose": "Accept short WebVTT timestamps.",
      "file": "subtitle-corpus-vtt-clean.vtt",
      "input": "WEBVTT\n\n00:01.000 --> 00:04.000\nMap the room.\n",
      "structuralFindings": [],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 0,
        "warnings": 0
      },
      "explanation": "Accept short WebVTT timestamps."
    },
    {
      "id": "vtt-settings",
      "title": "WebVTT valid positioning settings",
      "format": "VTT",
      "purpose": "Keep valid line, position, size and alignment settings distinct from malformed timestamps.",
      "file": "subtitle-corpus-vtt-settings.vtt",
      "input": "WEBVTT\n\n00:01.000 --> 00:04.000 line:90% position:50% size:80% align:center\nMap the room.\n",
      "structuralFindings": [],
      "editorialWarnings": [],
      "scopeWarnings": [
        {
          "cue": 1,
          "code": "settings-unchecked",
          "message": "WebVTT cue settings are not validated; inspect positioning in the delivery player."
        }
      ],
      "expected": {
        "cueCount": 1,
        "errors": 0,
        "warnings": 1
      },
      "explanation": "These settings use forms defined by the pinned draft. The checker leaves all settings unvalidated and asks for player inspection; this is a scope warning, not an editorial defect."
    },
    {
      "id": "vtt-bom",
      "title": "WebVTT UTF-8 BOM",
      "format": "VTT",
      "purpose": "Accept an optional initial byte-order mark with original UTF-8 text.",
      "file": "subtitle-corpus-vtt-bom.vtt",
      "input": "﻿WEBVTT\n\n00:01.000 --> 00:04.000\nCafé 🌍\n",
      "structuralFindings": [],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 0,
        "warnings": 0
      },
      "explanation": "Accept an optional initial byte-order mark with original UTF-8 text."
    },
    {
      "id": "vtt-note-identifier",
      "title": "WebVTT comment and identifier",
      "format": "VTT",
      "purpose": "Skip an original NOTE block and accept a nonnumeric cue identifier.",
      "file": "subtitle-corpus-vtt-note-identifier.vtt",
      "input": "WEBVTT\n\nNOTE original practice note\nNo source recording exists.\n\nroom-label\n00:01.000 --> 00:04.000\nMap the room.\n",
      "structuralFindings": [],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 1,
        "errors": 0,
        "warnings": 0
      },
      "explanation": "Skip an original NOTE block and accept a nonnumeric cue identifier."
    },
    {
      "id": "vtt-comma",
      "title": "WebVTT wrong separator",
      "format": "VTT",
      "purpose": "Reject SRT-style commas in WebVTT.",
      "file": "subtitle-corpus-vtt-comma.vtt",
      "input": "WEBVTT\n\n00:01,000 --> 00:04,000\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "invalid-timestamp-vtt",
          "message": "Invalid VTT timestamp; check separators and minute/second ranges."
        },
        {
          "cue": "",
          "code": "no-readable-cues",
          "message": "No readable timed cues found."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 0,
        "errors": 2,
        "warnings": 0
      },
      "explanation": "Reject SRT-style commas in WebVTT."
    },
    {
      "id": "vtt-range",
      "title": "WebVTT second range",
      "format": "VTT",
      "purpose": "Reject a seconds component of 60.",
      "file": "subtitle-corpus-vtt-range.vtt",
      "input": "WEBVTT\n\n00:60.000 --> 01:04.000\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "invalid-timestamp-vtt",
          "message": "Invalid VTT timestamp; check separators and minute/second ranges."
        },
        {
          "cue": "",
          "code": "no-readable-cues",
          "message": "No readable timed cues found."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 0,
        "errors": 2,
        "warnings": 0
      },
      "explanation": "Reject a seconds component of 60."
    },
    {
      "id": "vtt-missing-end",
      "title": "WebVTT missing end timestamp",
      "format": "VTT",
      "purpose": "Require an end timestamp.",
      "file": "subtitle-corpus-vtt-missing-end.vtt",
      "input": "WEBVTT\n\n00:01.000 -->\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": 1,
          "code": "malformed-timing",
          "message": "Missing or malformed timing line."
        },
        {
          "cue": "",
          "code": "no-readable-cues",
          "message": "No readable timed cues found."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 0,
        "errors": 2,
        "warnings": 0
      },
      "explanation": "Require an end timestamp."
    },
    {
      "id": "vtt-start-order",
      "title": "WebVTT decreasing start times",
      "format": "VTT",
      "purpose": "Classify decreasing start times as a structural violation of the pinned draft.",
      "file": "subtitle-corpus-vtt-start-order.vtt",
      "input": "WEBVTT\n\n00:05.000 --> 00:08.000\nFirst.\n\n00:01.000 --> 00:04.000\nSecond.\n",
      "structuralFindings": [
        {
          "cue": 2,
          "code": "start-order",
          "message": "Cue starts before the preceding cue."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 2,
        "errors": 1,
        "warnings": 0
      },
      "explanation": "The start times are out of order, but these two intervals do not intersect. Do not invent an overlap warning from the largest earlier end time."
    },
    {
      "id": "vtt-overlap",
      "title": "WebVTT intentional overlap",
      "format": "VTT",
      "purpose": "Allow overlapping cues whose start times remain ordered.",
      "file": "subtitle-corpus-vtt-overlap.vtt",
      "input": "WEBVTT\n\n00:01.000 --> 00:05.000\nLeft.\n\n00:02.000 --> 00:04.000\nRight.\n",
      "structuralFindings": [],
      "editorialWarnings": [
        {
          "cue": 2,
          "code": "overlap",
          "message": "Cue overlaps an earlier cue; confirm whether simultaneous captions are intentional."
        }
      ],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 2,
        "errors": 0,
        "warnings": 1
      },
      "explanation": "The pinned draft permits overlapping subtitle cues. Placement and simultaneous voices need editorial review; chapters are outside this corpus."
    },
    {
      "id": "vtt-header-separator",
      "title": "WebVTT missing header separator",
      "format": "VTT",
      "purpose": "Require a blank line after the WEBVTT signature.",
      "file": "subtitle-corpus-vtt-header-separator.vtt",
      "input": "WEBVTT\n00:01.000 --> 00:04.000\nMap the room.\n",
      "structuralFindings": [
        {
          "cue": "",
          "code": "header-separator",
          "message": "Separate the WEBVTT header from the first cue with a blank line."
        },
        {
          "cue": "",
          "code": "no-readable-cues",
          "message": "No readable timed cues found."
        }
      ],
      "editorialWarnings": [],
      "scopeWarnings": [],
      "expected": {
        "cueCount": 0,
        "errors": 2,
        "warnings": 0
      },
      "explanation": "Require a blank line after the WEBVTT signature."
    }
  ]
}
