FAILURE MAP
← Case archive

FA-78776 / Broadcast timecode arithmetic / Open access

Operator timecode entry normalization: digit count limit · case 01

A nine-digit entry is accepted and truncated silently.

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

ROOT CAUSE

The digit limit allows nine digits.

VERIFIED REPAIR

Allow at most eight digits.

Unsuccessful approach: Rejecting eight digits refuses a complete HHMMSSFF entry.

Case contract

Normalize typed timecode. Separators ":", ";" and "." are equivalent. With separators, up to four numeric fields fill from the right (frames last). Without separators, up to eight digits are right-aligned into HH MM SS FF pairs. Field overflow carries through the total frame count, which wraps at 24 hours. Invalid entry returns None.

Why this case matters

Timecode arithmetic errors misplace edits, commercial breaks and captions against the broadcast clock.

1 / The failure

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

N = 1
observations = []
def solve(s, fps):
    s=s.replace(';',':').replace('.',':')
    if ':' in s:
        parts=s.split(':')
        if len(parts)>4 or not all(p.isdigit() for p in parts):
            return None
        vals=[0]*(4-len(parts))+[int(p) for p in parts]
    else:
        if not s.isdigit() or len(s)>9:
            return None
        d=s.zfill(8)
        vals=[int(d[i:i+2]) for i in range(0,8,2)]
    h,m,sec,f=vals
    n=((h*60+m)*60+sec)*fps+f
    n%=86400*fps
    return '%02d:%02d:%02d:%02d'%(n//(3600*fps),n//(60*fps)%60,n//fps%60,n%fps)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: digit count limit', ['123456789', 25], None), ('regression variant: digit count limit', ['123456789', 30], None), ('partial repair probe: digit count limit', ['12345678', 30], '12:34:58:18'), ('partial repair variant: digit count limit', ['12345678', 25], '12:34:59:03'), ('boundary control', ['100', 25], '00:00:01:00'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('normal control', ['1:2', 25], '00:00:01:02'), ('normal control', ['59.10', 24], '00:00:59:10'), ('normal control', ['59.99', 24], '00:01:03:03')], [('regression: digit count limit', ['123456789', 24], None), ('regression variant: digit count limit', ['123456789', 25], None), ('partial repair probe: digit count limit', ['12345678', 24], '12:34:59:06'), ('partial repair variant: digit count limit', ['12345678', 30], '12:34:58:18'), ('boundary control', ['1:2', 25], '00:00:01:02'), ('boundary control', ['100', 25], '00:00:01:00'), ('normal control', ['100', 30], '00:00:01:00'), ('normal control', ['0:23:23', 24], '00:00:23:23'), ('normal control', ['10', 24], '00:00:00:10')], [('regression: digit count limit', ['123456789', 30], None), ('regression variant: digit count limit', ['123456789', 24], None), ('partial repair probe: digit count limit', ['23595924', 25], '23:59:59:24'), ('partial repair variant: digit count limit', ['12345678', 24], '12:34:59:06'), ('boundary control', ['99', 25], '00:00:03:24'), ('boundary control', ['1:2', 25], '00:00:01:02'), ('normal control', ['100', 24], '00:00:01:00'), ('normal control', ['30', 24], '00:00:01:06'), ('normal control', ['61:59:59:24:0', 25], None)], [('regression: digit count limit', ['123456789', 25], None), ('regression variant: digit count limit', ['123456789', 30], None), ('partial repair probe: digit count limit', ['12345678', 25], '12:34:59:03'), ('partial repair variant: digit count limit', ['23595924', 25], '23:59:59:24'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('boundary control', ['99', 25], '00:00:03:24'), ('normal control', ['1000', 24], '00:00:10:00'), ('normal control', ['23:30:30', 24], '00:23:31:06'), ('normal control', ['59.2', 24], '00:00:59:02')], [('regression: digit count limit', ['123456789', 24], None), ('regression variant: digit count limit', ['123456789', 25], None), ('partial repair probe: digit count limit', ['12345678', 30], '12:34:58:18'), ('partial repair variant: digit count limit', ['12345678', 25], '12:34:59:03'), ('boundary control', ['100', 25], '00:00:01:00'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('normal control', ['1:30:10', 30], '00:01:30:10'), ('normal control', ['x1', 25], None), ('normal control', ['59:59:2', 30], '00:59:59:02')]]
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: digit count limit12:34:59:03NoneFailed
regression variant: digit count limit12:34:58:18NoneFailed
partial repair probe: digit count limit12:34:58:1812:34:58:18Passed
partial repair variant: digit count limit12:34:59:0312:34:59:03Passed
boundary control00:00:01:0000:00:01:00Passed
boundary control01:02:03:0401:02:03:04Passed
normal control00:00:01:0200:00:01:02Passed
normal control00:00:59:1000:00:59:10Passed
normal control00:01:03:0300:01:03:03Passed

SHA-256 / e2ea6164f00c000ca6df737ed4c249ce9f6401e18ea2213e17299c20313e2d47

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(s, fps):
    s=s.replace(';',':').replace('.',':')
    if ':' in s:
        parts=s.split(':')
        if len(parts)>4 or not all(p.isdigit() for p in parts):
            return None
        vals=[0]*(4-len(parts))+[int(p) for p in parts]
    else:
        if not s.isdigit() or len(s)>=8:
            return None
        d=s.zfill(8)
        vals=[int(d[i:i+2]) for i in range(0,8,2)]
    h,m,sec,f=vals
    n=((h*60+m)*60+sec)*fps+f
    n%=86400*fps
    return '%02d:%02d:%02d:%02d'%(n//(3600*fps),n//(60*fps)%60,n//fps%60,n%fps)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: digit count limit', ['123456789', 25], None), ('regression variant: digit count limit', ['123456789', 30], None), ('partial repair probe: digit count limit', ['12345678', 30], '12:34:58:18'), ('partial repair variant: digit count limit', ['12345678', 25], '12:34:59:03'), ('boundary control', ['100', 25], '00:00:01:00'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('normal control', ['1:2', 25], '00:00:01:02'), ('normal control', ['59.10', 24], '00:00:59:10'), ('normal control', ['59.99', 24], '00:01:03:03')], [('regression: digit count limit', ['123456789', 24], None), ('regression variant: digit count limit', ['123456789', 25], None), ('partial repair probe: digit count limit', ['12345678', 24], '12:34:59:06'), ('partial repair variant: digit count limit', ['12345678', 30], '12:34:58:18'), ('boundary control', ['1:2', 25], '00:00:01:02'), ('boundary control', ['100', 25], '00:00:01:00'), ('normal control', ['100', 30], '00:00:01:00'), ('normal control', ['0:23:23', 24], '00:00:23:23'), ('normal control', ['10', 24], '00:00:00:10')], [('regression: digit count limit', ['123456789', 30], None), ('regression variant: digit count limit', ['123456789', 24], None), ('partial repair probe: digit count limit', ['23595924', 25], '23:59:59:24'), ('partial repair variant: digit count limit', ['12345678', 24], '12:34:59:06'), ('boundary control', ['99', 25], '00:00:03:24'), ('boundary control', ['1:2', 25], '00:00:01:02'), ('normal control', ['100', 24], '00:00:01:00'), ('normal control', ['30', 24], '00:00:01:06'), ('normal control', ['61:59:59:24:0', 25], None)], [('regression: digit count limit', ['123456789', 25], None), ('regression variant: digit count limit', ['123456789', 30], None), ('partial repair probe: digit count limit', ['12345678', 25], '12:34:59:03'), ('partial repair variant: digit count limit', ['23595924', 25], '23:59:59:24'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('boundary control', ['99', 25], '00:00:03:24'), ('normal control', ['1000', 24], '00:00:10:00'), ('normal control', ['23:30:30', 24], '00:23:31:06'), ('normal control', ['59.2', 24], '00:00:59:02')], [('regression: digit count limit', ['123456789', 24], None), ('regression variant: digit count limit', ['123456789', 25], None), ('partial repair probe: digit count limit', ['12345678', 30], '12:34:58:18'), ('partial repair variant: digit count limit', ['12345678', 25], '12:34:59:03'), ('boundary control', ['100', 25], '00:00:01:00'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('normal control', ['1:30:10', 30], '00:01:30:10'), ('normal control', ['x1', 25], None), ('normal control', ['59:59:2', 30], '00:59:59:02')]]
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: digit count limitNoneNonePassed
regression variant: digit count limitNoneNonePassed
partial repair probe: digit count limitNone12:34:58:18Failed
partial repair variant: digit count limitNone12:34:59:03Failed
boundary control00:00:01:0000:00:01:00Passed
boundary control01:02:03:0401:02:03:04Passed
normal control00:00:01:0200:00:01:02Passed
normal control00:00:59:1000:00:59:10Passed
normal control00:01:03:0300:01:03:03Passed

SHA-256 / 4a2e61c19b73fd93c6417903a9ac7cdf50ff95082b8f7c7378c3d0d5714c24bd

3 / The verified repair

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

N = 1
observations = []
def solve(s, fps):
    s=s.replace(';',':').replace('.',':')
    if ':' in s:
        parts=s.split(':')
        if len(parts)>4 or not all(p.isdigit() for p in parts):
            return None
        vals=[0]*(4-len(parts))+[int(p) for p in parts]
    else:
        if not s.isdigit() or len(s)>8:
            return None
        d=s.zfill(8)
        vals=[int(d[i:i+2]) for i in range(0,8,2)]
    h,m,sec,f=vals
    n=((h*60+m)*60+sec)*fps+f
    n%=86400*fps
    return '%02d:%02d:%02d:%02d'%(n//(3600*fps),n//(60*fps)%60,n//fps%60,n%fps)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: digit count limit', ['123456789', 25], None), ('regression variant: digit count limit', ['123456789', 30], None), ('partial repair probe: digit count limit', ['12345678', 30], '12:34:58:18'), ('partial repair variant: digit count limit', ['12345678', 25], '12:34:59:03'), ('boundary control', ['100', 25], '00:00:01:00'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('normal control', ['1:2', 25], '00:00:01:02'), ('normal control', ['59.10', 24], '00:00:59:10'), ('normal control', ['59.99', 24], '00:01:03:03')], [('regression: digit count limit', ['123456789', 24], None), ('regression variant: digit count limit', ['123456789', 25], None), ('partial repair probe: digit count limit', ['12345678', 24], '12:34:59:06'), ('partial repair variant: digit count limit', ['12345678', 30], '12:34:58:18'), ('boundary control', ['1:2', 25], '00:00:01:02'), ('boundary control', ['100', 25], '00:00:01:00'), ('normal control', ['100', 30], '00:00:01:00'), ('normal control', ['0:23:23', 24], '00:00:23:23'), ('normal control', ['10', 24], '00:00:00:10')], [('regression: digit count limit', ['123456789', 30], None), ('regression variant: digit count limit', ['123456789', 24], None), ('partial repair probe: digit count limit', ['23595924', 25], '23:59:59:24'), ('partial repair variant: digit count limit', ['12345678', 24], '12:34:59:06'), ('boundary control', ['99', 25], '00:00:03:24'), ('boundary control', ['1:2', 25], '00:00:01:02'), ('normal control', ['100', 24], '00:00:01:00'), ('normal control', ['30', 24], '00:00:01:06'), ('normal control', ['61:59:59:24:0', 25], None)], [('regression: digit count limit', ['123456789', 25], None), ('regression variant: digit count limit', ['123456789', 30], None), ('partial repair probe: digit count limit', ['12345678', 25], '12:34:59:03'), ('partial repair variant: digit count limit', ['23595924', 25], '23:59:59:24'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('boundary control', ['99', 25], '00:00:03:24'), ('normal control', ['1000', 24], '00:00:10:00'), ('normal control', ['23:30:30', 24], '00:23:31:06'), ('normal control', ['59.2', 24], '00:00:59:02')], [('regression: digit count limit', ['123456789', 24], None), ('regression variant: digit count limit', ['123456789', 25], None), ('partial repair probe: digit count limit', ['12345678', 30], '12:34:58:18'), ('partial repair variant: digit count limit', ['12345678', 25], '12:34:59:03'), ('boundary control', ['100', 25], '00:00:01:00'), ('boundary control', ['1.2.3.4', 25], '01:02:03:04'), ('normal control', ['1:30:10', 30], '00:01:30:10'), ('normal control', ['x1', 25], None), ('normal control', ['59:59:2', 30], '00:59:59:02')]]
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: digit count limitNoneNonePassed
regression variant: digit count limitNoneNonePassed
partial repair probe: digit count limit12:34:58:1812:34:58:18Passed
partial repair variant: digit count limit12:34:59:0312:34:59:03Passed
boundary control00:00:01:0000:00:01:00Passed
boundary control01:02:03:0401:02:03:04Passed
normal control00:00:01:0200:00:01:02Passed
normal control00:00:59:1000:00:59:10Passed
normal control00:01:03:0300:01:03:03Passed

SHA-256 / f7dda46301ac888d94625d6ca2b26b07250a7b9e1c2bb434d1651796a0794235

Verification & scope

A deterministic bounded teaching model with a stipulated toy contract; it does not claim conformance to SMPTE or any broadcast 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:38.562161+00:00.

Case digest / 1f4601597e255cbf6a4fddff40bcaac817518530ed9aad7b4ca95f2c0cbf0eeb