FAILURE MAP
← Case archive

FA-78166 / Subtitle cue timing / Open access

WebVTT cue timing line parsing: hour digit count · case 01

Cues after hour 99 in long recordings fail to parse.

Verified by executionVariant 1 · 9 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The hour group allows exactly two digits.

VERIFIED REPAIR

Allow two or more hour digits.

Unsuccessful approach: Allowing one or two digits accepts illegal single-digit hours and still rejects hour 100.

Case contract

Parse "START --> END [settings...]" (whitespace separated). Timestamps are [hh:]mm:ss.ttt with hours of two or more digits, minutes and seconds exactly two digits below 60, and exactly three fraction digits after a period. END must be after START. Return [start_ms,end_ms,settings joined by single spaces] or None.

Why this case matters

Subtitle timing defects shift, hide or overlap captions that viewers depend on for comprehension and accessibility.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import re
N = 1
observations = []
def solve(line):
    parts=line.split()
    if len(parts)<3 or parts[1]!='-->':
        return None
    def ts(x):
        m=re.fullmatch(r'(?:(\d{2}):)?(\d{2}):(\d{2})\.(\d{3})',x)
        if not m:
            return None
        h,mi,se,f=m.groups()
        if int(mi)>59 or int(se)>59:
            return None
        return int(h or 0)*3600000+int(mi)*60000+int(se)*1000+int(f)
    a=ts(parts[0]); b=ts(parts[2])
    if a is None or b is None or b<=a:
        return None
    return [a,b,' '.join(parts[3:])]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: hour digit count', ['100:00:00.000 --> 100:00:01.000 align:start'], [360000000, 360001000, 'align:start']), ('regression variant: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('partial repair probe: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('partial repair variant: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('normal control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['59:09.5 --> 00:02.000 align:start'], None), ('normal control', ['100:01:60,500 --> 00:00:60.5 align:start'], None)], [('regression: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('regression variant: hour digit count', ['00:59.500 --> 100:00:00.000 line:0 position:10%'], [59500, 360000000, 'line:0 position:10%']), ('partial repair probe: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('partial repair variant: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['00:5:00.000 -> 00:5:00.000'], None), ('normal control', ['01:01:09.5 --> 60:09.5 size:50% align:end'], None), ('normal control', ['01:60:59.999 --> 00:00.001 line:0 position:10%'], None)], [('regression: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('regression variant: hour digit count', ['59:09.500 --> 100:00:00.000 line:0 position:10%'], [3549500, 360000000, 'line:0 position:10%']), ('partial repair probe: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('partial repair variant: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('normal control', ['01:60:00.500 --> 5:60,500 line:0 position:10%'], None), ('normal control', ['100:01:00,500 --> 01:00:00.000 align:start'], None), ('normal control', ['60:59.500 --> 100:00:00.000'], None)], [('regression: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('regression variant: hour digit count', ['100:00:00.000 --> 100:00:01.000 align:start'], [360000000, 360001000, 'align:start']), ('partial repair probe: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('partial repair variant: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('normal control', ['60:60.999 --> 00:00.001'], None), ('normal control', ['01:59:59,500 --> 01:59:59,500 size:50% align:end'], None), ('normal control', ['59:60.5 --> 100:00:00.000 line:0 position:10%'], None)], [('regression: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('regression variant: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('partial repair probe: hour digit count', ['00:59.500 --> 100:00:00.000 line:0 position:10%'], [59500, 360000000, 'line:0 position:10%']), ('partial repair variant: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['01:5:60.500 --> 00:00.001 size:50% align:end'], None), ('normal control', ['100:00:59.000 --> 00:02.000 size:50% align:end'], None), ('normal control', ['100:59:09.000 --> 100:59:09.000'], None)]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: hour digit countNone[360000000, 360001000, 'align:start']Failed
regression variant: hour digit countNone[500, 360060000, 'align:start']Failed
partial repair probe: hour digit countNone[3549999, 360000000, '']Failed
partial repair variant: hour digit countNone[3600999, 360000000, 'size:50% align:end']Failed
boundary control[1000, 2000, ''][1000, 2000, '']Passed
boundary controlNoneNonePassed
normal control[59999, 60000, 'line:0 size:50%'][59999, 60000, 'line:0 size:50%']Passed
normal controlNoneNonePassed
normal controlNoneNonePassed

SHA-256 / 9e3d222bd06a0aeac75fc5da7848025bfacc0a504ad86073ce95b909563c4cb2

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import re
N = 1
observations = []
def solve(line):
    parts=line.split()
    if len(parts)<3 or parts[1]!='-->':
        return None
    def ts(x):
        m=re.fullmatch(r'(?:(\d{1,2}):)?(\d{2}):(\d{2})\.(\d{3})',x)
        if not m:
            return None
        h,mi,se,f=m.groups()
        if int(mi)>59 or int(se)>59:
            return None
        return int(h or 0)*3600000+int(mi)*60000+int(se)*1000+int(f)
    a=ts(parts[0]); b=ts(parts[2])
    if a is None or b is None or b<=a:
        return None
    return [a,b,' '.join(parts[3:])]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: hour digit count', ['100:00:00.000 --> 100:00:01.000 align:start'], [360000000, 360001000, 'align:start']), ('regression variant: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('partial repair probe: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('partial repair variant: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('normal control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['59:09.5 --> 00:02.000 align:start'], None), ('normal control', ['100:01:60,500 --> 00:00:60.5 align:start'], None)], [('regression: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('regression variant: hour digit count', ['00:59.500 --> 100:00:00.000 line:0 position:10%'], [59500, 360000000, 'line:0 position:10%']), ('partial repair probe: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('partial repair variant: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['00:5:00.000 -> 00:5:00.000'], None), ('normal control', ['01:01:09.5 --> 60:09.5 size:50% align:end'], None), ('normal control', ['01:60:59.999 --> 00:00.001 line:0 position:10%'], None)], [('regression: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('regression variant: hour digit count', ['59:09.500 --> 100:00:00.000 line:0 position:10%'], [3549500, 360000000, 'line:0 position:10%']), ('partial repair probe: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('partial repair variant: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('normal control', ['01:60:00.500 --> 5:60,500 line:0 position:10%'], None), ('normal control', ['100:01:00,500 --> 01:00:00.000 align:start'], None), ('normal control', ['60:59.500 --> 100:00:00.000'], None)], [('regression: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('regression variant: hour digit count', ['100:00:00.000 --> 100:00:01.000 align:start'], [360000000, 360001000, 'align:start']), ('partial repair probe: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('partial repair variant: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('normal control', ['60:60.999 --> 00:00.001'], None), ('normal control', ['01:59:59,500 --> 01:59:59,500 size:50% align:end'], None), ('normal control', ['59:60.5 --> 100:00:00.000 line:0 position:10%'], None)], [('regression: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('regression variant: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('partial repair probe: hour digit count', ['00:59.500 --> 100:00:00.000 line:0 position:10%'], [59500, 360000000, 'line:0 position:10%']), ('partial repair variant: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['01:5:60.500 --> 00:00.001 size:50% align:end'], None), ('normal control', ['100:00:59.000 --> 00:02.000 size:50% align:end'], None), ('normal control', ['100:59:09.000 --> 100:59:09.000'], None)]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: hour digit countNone[360000000, 360001000, 'align:start']Failed
regression variant: hour digit countNone[500, 360060000, 'align:start']Failed
partial repair probe: hour digit countNone[3549999, 360000000, '']Failed
partial repair variant: hour digit countNone[3600999, 360000000, 'size:50% align:end']Failed
boundary control[1000, 2000, ''][1000, 2000, '']Passed
boundary controlNoneNonePassed
normal control[59999, 60000, 'line:0 size:50%'][59999, 60000, 'line:0 size:50%']Passed
normal controlNoneNonePassed
normal controlNoneNonePassed

SHA-256 / 0e55410c2d7a2455658267b237d756604576c21526dd8acc2d6f9517fc8d6703

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import re
N = 1
observations = []
def solve(line):
    parts=line.split()
    if len(parts)<3 or parts[1]!='-->':
        return None
    def ts(x):
        m=re.fullmatch(r'(?:(\d{2,}):)?(\d{2}):(\d{2})\.(\d{3})',x)
        if not m:
            return None
        h,mi,se,f=m.groups()
        if int(mi)>59 or int(se)>59:
            return None
        return int(h or 0)*3600000+int(mi)*60000+int(se)*1000+int(f)
    a=ts(parts[0]); b=ts(parts[2])
    if a is None or b is None or b<=a:
        return None
    return [a,b,' '.join(parts[3:])]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: hour digit count', ['100:00:00.000 --> 100:00:01.000 align:start'], [360000000, 360001000, 'align:start']), ('regression variant: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('partial repair probe: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('partial repair variant: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('normal control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['59:09.5 --> 00:02.000 align:start'], None), ('normal control', ['100:01:60,500 --> 00:00:60.5 align:start'], None)], [('regression: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('regression variant: hour digit count', ['00:59.500 --> 100:00:00.000 line:0 position:10%'], [59500, 360000000, 'line:0 position:10%']), ('partial repair probe: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('partial repair variant: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['00:5:00.000 -> 00:5:00.000'], None), ('normal control', ['01:01:09.5 --> 60:09.5 size:50% align:end'], None), ('normal control', ['01:60:59.999 --> 00:00.001 line:0 position:10%'], None)], [('regression: hour digit count', ['59:09.999 --> 100:00:00.000'], [3549999, 360000000, '']), ('regression variant: hour digit count', ['59:09.500 --> 100:00:00.000 line:0 position:10%'], [3549500, 360000000, 'line:0 position:10%']), ('partial repair probe: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('partial repair variant: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('normal control', ['01:60:00.500 --> 5:60,500 line:0 position:10%'], None), ('normal control', ['100:01:00,500 --> 01:00:00.000 align:start'], None), ('normal control', ['60:59.500 --> 100:00:00.000'], None)], [('regression: hour digit count', ['00:01:09.500 --> 100:00:00.000 line:0 position:10%'], [69500, 360000000, 'line:0 position:10%']), ('regression variant: hour digit count', ['100:00:00.000 --> 100:00:01.000 align:start'], [360000000, 360001000, 'align:start']), ('partial repair probe: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('partial repair variant: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('boundary control', ['00:01.000 --> 00:02.000'], [1000, 2000, '']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('normal control', ['60:60.999 --> 00:00.001'], None), ('normal control', ['01:59:59,500 --> 01:59:59,500 size:50% align:end'], None), ('normal control', ['59:60.5 --> 100:00:00.000 line:0 position:10%'], None)], [('regression: hour digit count', ['59:59.999 --> 100:00:59.999 size:50% align:end'], [3599999, 360059999, 'size:50% align:end']), ('regression variant: hour digit count', ['01:00:00.999 --> 100:00:00.000 size:50% align:end'], [3600999, 360000000, 'size:50% align:end']), ('partial repair probe: hour digit count', ['00:59.500 --> 100:00:00.000 line:0 position:10%'], [59500, 360000000, 'line:0 position:10%']), ('partial repair variant: hour digit count', ['00:00:00.500 --> 100:01:00.000 align:start'], [500, 360060000, 'align:start']), ('boundary control', ['00:01.000 --> 00:01.000'], None), ('boundary control', ['00:59.999 --> 01:00.000 line:0 size:50%'], [59999, 60000, 'line:0 size:50%']), ('normal control', ['01:5:60.500 --> 00:00.001 size:50% align:end'], None), ('normal control', ['100:00:59.000 --> 00:02.000 size:50% align:end'], None), ('normal control', ['100:59:09.000 --> 100:59:09.000'], None)]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: hour digit count[360000000, 360001000, 'align:start'][360000000, 360001000, 'align:start']Passed
regression variant: hour digit count[500, 360060000, 'align:start'][500, 360060000, 'align:start']Passed
partial repair probe: hour digit count[3549999, 360000000, ''][3549999, 360000000, '']Passed
partial repair variant: hour digit count[3600999, 360000000, 'size:50% align:end'][3600999, 360000000, 'size:50% align:end']Passed
boundary control[1000, 2000, ''][1000, 2000, '']Passed
boundary controlNoneNonePassed
normal control[59999, 60000, 'line:0 size:50%'][59999, 60000, 'line:0 size:50%']Passed
normal controlNoneNonePassed
normal controlNoneNonePassed

SHA-256 / e25edf0962b3da9399822c884b8068b02a36a9444a4da558e4513361adaaad04

Verification & scope

A deterministic bounded teaching model with a stipulated toy contract; it does not claim conformance to any subtitle standard. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:49:32.721818+00:00.

Case digest / baba7d18cfd46e27e87ba39e9481535ac0caffb3fd7e610f48923743f8e6d34d