FAILURE MAP
← Case archive

FA-77841 / Subtitle cue timing / Open access

SRT timestamp parsing: fraction padding · case 01

A cue written as 00:00:01,5 starts at 1.005 s instead of 1.5 s.

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

ROOT CAUSE

Short millisecond fractions are left-padded with frac.rjust(3,'0'), treating ',5' as 5 ms.

VERIFIED REPAIR

Right-pad the fraction to three digits before converting it to milliseconds.

Unsuccessful approach: Converting the raw fraction digits with int(frac) still reads one- and two-digit fractions as tiny millisecond counts.

Case contract

Parse an SRT timestamp HH:MM:SS,mmm to integer milliseconds. Hours have 2 or more digits, minutes and seconds are below 60, the fraction has 1 to 3 digits and is right-padded (",5" means 500 ms), "." is accepted as the separator, surrounding whitespace (including a CR from CRLF files) is ignored; invalid text returns 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

N = 1
observations = []
def solve(s):
    s=s.strip()
    parts=s.replace('.',',').split(',')
    if len(parts)!=2: return None
    hms,frac=parts
    fields=hms.split(':')
    if len(fields)!=3: return None
    if not all(p.isdigit() for p in fields) or not frac.isdigit(): return None
    if len(frac)>3: return None
    h,mi,se=int(fields[0]),int(fields[1]),int(fields[2])
    if mi>=60 or se>=60: return None
    ms=int(frac.rjust(3,'0'))
    return h*3600000+mi*60000+se*1000+ms
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: fraction padding', ['00:00:01,5'], 1500), ('regression variant: fraction padding', [' 100:00:00,07'], 360000070), ('partial repair probe: fraction padding', ['02:30:42,5\t'], 9042500), ('partial repair variant: fraction padding', ['10:30:59,12\t'], 37859120), ('boundary control', ['00:00:00,000'], 0), ('boundary control', ['00:60:00,000'], None), ('normal control', ['01:02:03.004'], 3723004), ('normal control', ['100:00:00,000'], 360000000), ('normal control', ['00:61:00;5 \r'], None)], [('regression: fraction padding', [' 00:05:00.5 '], 300500), ('regression variant: fraction padding', [' 100:00:01.50\r'], 360001500), ('partial repair probe: fraction padding', ['00:30:59,12 '], 1859120), ('partial repair variant: fraction padding', ['123:05:01.12\t'], 443101120), ('boundary control', ['01:02:03.004'], 3723004), ('boundary control', ['100:00:00,000'], 360000000), ('normal control', ['123:60:59,5'], None), ('normal control', ['99:00:00.500\r'], 356400500), ('normal control', [' 00:30:60,500'], None)], [('regression: fraction padding', ['02:30:42,5\t'], 9042500), ('regression variant: fraction padding', [' 100:59:59,12'], 363599120), ('partial repair probe: fraction padding', [' 123:59:42,50 '], 446382500), ('partial repair variant: fraction padding', [' 02:30:59,12 '], 9059120), ('boundary control', ['00:59:59,999\r'], 3599999), ('boundary control', ['00:00:00,000'], 0), ('normal control', ['00:00:60.1234 '], None), ('normal control', ['10:61:61. \r'], None), ('normal control', ['00:30:59;12'], None)], [('regression: fraction padding', ['00:30:59,12 '], 1859120), ('regression variant: fraction padding', ['02:59:42,12 '], 10782120), ('partial repair probe: fraction padding', [' 100:00:00,07'], 360000070), ('partial repair variant: fraction padding', [' 100:05:42.50'], 360342500), ('boundary control', ['00:60:00,000'], None), ('boundary control', ['01:02:03.004'], 3723004), ('normal control', ['00:00:60,1234\r'], None), ('normal control', ['00:00:60,07'], None), ('normal control', [' 00:61:42,000'], None)], [('regression: fraction padding', [' 123:59:42,50 '], 446382500), ('regression variant: fraction padding', ['10:30:59,12\t'], 37859120), ('partial repair probe: fraction padding', [' 100:00:01.50\r'], 360001500), ('partial repair variant: fraction padding', ['100:30:00,5'], 361800500), ('boundary control', ['100:00:00,000'], 360000000), ('boundary control', ['00:59:59,999\r'], 3599999), ('normal control', ['01:30:01,500 \r'], 5401500), ('normal control', ['01:05:00,500\r'], 3900500), ('normal control', ['100:30:42,500\r'], 361842500)]]
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: fraction padding10051500Failed
regression variant: fraction padding360000007360000070Failed
partial repair probe: fraction padding90420059042500Failed
partial repair variant: fraction padding3785901237859120Failed
boundary control00Passed
boundary controlNoneNonePassed
normal control37230043723004Passed
normal control360000000360000000Passed
normal controlNoneNonePassed

SHA-256 / 3f5d589bd5535b5b1caeed48328422f1eb3b9e9614cdd7bff9e46b7cd58d4fbe

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(s):
    s=s.strip()
    parts=s.replace('.',',').split(',')
    if len(parts)!=2: return None
    hms,frac=parts
    fields=hms.split(':')
    if len(fields)!=3: return None
    if not all(p.isdigit() for p in fields) or not frac.isdigit(): return None
    if len(frac)>3: return None
    h,mi,se=int(fields[0]),int(fields[1]),int(fields[2])
    if mi>=60 or se>=60: return None
    ms=int(frac)
    return h*3600000+mi*60000+se*1000+ms
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: fraction padding', ['00:00:01,5'], 1500), ('regression variant: fraction padding', [' 100:00:00,07'], 360000070), ('partial repair probe: fraction padding', ['02:30:42,5\t'], 9042500), ('partial repair variant: fraction padding', ['10:30:59,12\t'], 37859120), ('boundary control', ['00:00:00,000'], 0), ('boundary control', ['00:60:00,000'], None), ('normal control', ['01:02:03.004'], 3723004), ('normal control', ['100:00:00,000'], 360000000), ('normal control', ['00:61:00;5 \r'], None)], [('regression: fraction padding', [' 00:05:00.5 '], 300500), ('regression variant: fraction padding', [' 100:00:01.50\r'], 360001500), ('partial repair probe: fraction padding', ['00:30:59,12 '], 1859120), ('partial repair variant: fraction padding', ['123:05:01.12\t'], 443101120), ('boundary control', ['01:02:03.004'], 3723004), ('boundary control', ['100:00:00,000'], 360000000), ('normal control', ['123:60:59,5'], None), ('normal control', ['99:00:00.500\r'], 356400500), ('normal control', [' 00:30:60,500'], None)], [('regression: fraction padding', ['02:30:42,5\t'], 9042500), ('regression variant: fraction padding', [' 100:59:59,12'], 363599120), ('partial repair probe: fraction padding', [' 123:59:42,50 '], 446382500), ('partial repair variant: fraction padding', [' 02:30:59,12 '], 9059120), ('boundary control', ['00:59:59,999\r'], 3599999), ('boundary control', ['00:00:00,000'], 0), ('normal control', ['00:00:60.1234 '], None), ('normal control', ['10:61:61. \r'], None), ('normal control', ['00:30:59;12'], None)], [('regression: fraction padding', ['00:30:59,12 '], 1859120), ('regression variant: fraction padding', ['02:59:42,12 '], 10782120), ('partial repair probe: fraction padding', [' 100:00:00,07'], 360000070), ('partial repair variant: fraction padding', [' 100:05:42.50'], 360342500), ('boundary control', ['00:60:00,000'], None), ('boundary control', ['01:02:03.004'], 3723004), ('normal control', ['00:00:60,1234\r'], None), ('normal control', ['00:00:60,07'], None), ('normal control', [' 00:61:42,000'], None)], [('regression: fraction padding', [' 123:59:42,50 '], 446382500), ('regression variant: fraction padding', ['10:30:59,12\t'], 37859120), ('partial repair probe: fraction padding', [' 100:00:01.50\r'], 360001500), ('partial repair variant: fraction padding', ['100:30:00,5'], 361800500), ('boundary control', ['100:00:00,000'], 360000000), ('boundary control', ['00:59:59,999\r'], 3599999), ('normal control', ['01:30:01,500 \r'], 5401500), ('normal control', ['01:05:00,500\r'], 3900500), ('normal control', ['100:30:42,500\r'], 361842500)]]
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: fraction padding10051500Failed
regression variant: fraction padding360000007360000070Failed
partial repair probe: fraction padding90420059042500Failed
partial repair variant: fraction padding3785901237859120Failed
boundary control00Passed
boundary controlNoneNonePassed
normal control37230043723004Passed
normal control360000000360000000Passed
normal controlNoneNonePassed

SHA-256 / d1a6bb128c46dce47daf97c9abab25772c2c32819d49d5103ed46705b8e38a7f

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(s):
    s=s.strip()
    parts=s.replace('.',',').split(',')
    if len(parts)!=2: return None
    hms,frac=parts
    fields=hms.split(':')
    if len(fields)!=3: return None
    if not all(p.isdigit() for p in fields) or not frac.isdigit(): return None
    if len(frac)>3: return None
    h,mi,se=int(fields[0]),int(fields[1]),int(fields[2])
    if mi>=60 or se>=60: return None
    ms=int(frac.ljust(3,'0'))
    return h*3600000+mi*60000+se*1000+ms
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: fraction padding', ['00:00:01,5'], 1500), ('regression variant: fraction padding', [' 100:00:00,07'], 360000070), ('partial repair probe: fraction padding', ['02:30:42,5\t'], 9042500), ('partial repair variant: fraction padding', ['10:30:59,12\t'], 37859120), ('boundary control', ['00:00:00,000'], 0), ('boundary control', ['00:60:00,000'], None), ('normal control', ['01:02:03.004'], 3723004), ('normal control', ['100:00:00,000'], 360000000), ('normal control', ['00:61:00;5 \r'], None)], [('regression: fraction padding', [' 00:05:00.5 '], 300500), ('regression variant: fraction padding', [' 100:00:01.50\r'], 360001500), ('partial repair probe: fraction padding', ['00:30:59,12 '], 1859120), ('partial repair variant: fraction padding', ['123:05:01.12\t'], 443101120), ('boundary control', ['01:02:03.004'], 3723004), ('boundary control', ['100:00:00,000'], 360000000), ('normal control', ['123:60:59,5'], None), ('normal control', ['99:00:00.500\r'], 356400500), ('normal control', [' 00:30:60,500'], None)], [('regression: fraction padding', ['02:30:42,5\t'], 9042500), ('regression variant: fraction padding', [' 100:59:59,12'], 363599120), ('partial repair probe: fraction padding', [' 123:59:42,50 '], 446382500), ('partial repair variant: fraction padding', [' 02:30:59,12 '], 9059120), ('boundary control', ['00:59:59,999\r'], 3599999), ('boundary control', ['00:00:00,000'], 0), ('normal control', ['00:00:60.1234 '], None), ('normal control', ['10:61:61. \r'], None), ('normal control', ['00:30:59;12'], None)], [('regression: fraction padding', ['00:30:59,12 '], 1859120), ('regression variant: fraction padding', ['02:59:42,12 '], 10782120), ('partial repair probe: fraction padding', [' 100:00:00,07'], 360000070), ('partial repair variant: fraction padding', [' 100:05:42.50'], 360342500), ('boundary control', ['00:60:00,000'], None), ('boundary control', ['01:02:03.004'], 3723004), ('normal control', ['00:00:60,1234\r'], None), ('normal control', ['00:00:60,07'], None), ('normal control', [' 00:61:42,000'], None)], [('regression: fraction padding', [' 123:59:42,50 '], 446382500), ('regression variant: fraction padding', ['10:30:59,12\t'], 37859120), ('partial repair probe: fraction padding', [' 100:00:01.50\r'], 360001500), ('partial repair variant: fraction padding', ['100:30:00,5'], 361800500), ('boundary control', ['100:00:00,000'], 360000000), ('boundary control', ['00:59:59,999\r'], 3599999), ('normal control', ['01:30:01,500 \r'], 5401500), ('normal control', ['01:05:00,500\r'], 3900500), ('normal control', ['100:30:42,500\r'], 361842500)]]
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: fraction padding15001500Passed
regression variant: fraction padding360000070360000070Passed
partial repair probe: fraction padding90425009042500Passed
partial repair variant: fraction padding3785912037859120Passed
boundary control00Passed
boundary controlNoneNonePassed
normal control37230043723004Passed
normal control360000000360000000Passed
normal controlNoneNonePassed

SHA-256 / d94f63f769e5c12346de3e5b27a30e74a94f2062e120c2cda540ae11039dc500

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:29.406001+00:00.

Case digest / 0bedc4de7cbc6b3bc03dfb99d47048b88d76e57a0fa37b1999e5465d310e75eb