FA-81821 / MIDI event timing / Open access
MIDI Time Code quarter-frame assembly: hour does not wrap after 23 · case 01
A time of 23:59:59 plus the latency frames reports hour 24 instead of wrapping to 0.
ROOT CAUSE
The hour carry is added without reducing modulo 24.
VERIFIED REPAIR
Restore the hour wrap step so that it reads `(hours + mins // 60) % 24`.
Unsuccessful approach: Reducing before adding the carry still produces hour 24.
Case contract
Input the data bytes of received quarter-frame messages. The last eight must carry piece numbers 0..7 (high nibble) in order; low nibbles give frames (pieces 0,1 as low/high nibble), seconds (2,3), minutes (4,5) and hours (6 low nibble, piece 7 bit 0 as hours bit 4); piece 7 bits 1-2 give the rate code (0: 24, 1: 25, 2: 30 drop, 3: 30 fps). The reported time is the decoded time plus 2 frames, carried into seconds, minutes and hours (mod 24). Return [h, m, s, f, rate_code] or None.
Why this case matters
MIDI sequencers, file readers and synth drivers depend on exact event ordering and tick/time arithmetic.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if not isinstance(x, list) or len(x) < 8:
return None
last8 = x[-8:]
if [b >> 4 for b in last8] != list(range(8)):
return None
nib = [b & 0x0F for b in last8]
frames = nib[0] | (nib[1] << 4)
secs = nib[2] | (nib[3] << 4)
mins = nib[4] | (nib[5] << 4)
hours = nib[6] | ((nib[7] & 0x1) << 4)
rate = (nib[7] >> 1) & 0x3
fps = [24, 25, 30, 30][rate]
frames += 2
secs += frames // fps
frames %= fps
mins += secs // 60
secs %= 60
hours = hours + mins // 60
mins %= 60
return [hours, mins, secs, frames, rate]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 16, 32, 48, 64, 80, 96, 112], [0, 0, 0, 2, 0]), ([5, 17, 32, 48, 64, 80, 96, 114], [0, 0, 0, 23, 1]), ([4, 16, 35, 48, 66, 80, 97, 114], [1, 2, 3, 6, 1]), ([10, 16, 47, 48, 78, 81, 97, 117], [17, 30, 15, 12, 2]), ([0, 16, 32, 48, 64, 80, 100, 119], [20, 0, 0, 2, 3]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([8, 17, 43, 51, 75, 83, 97, 114], [2, 0, 0, 1, 1]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1])], [([10, 16, 47, 48, 78, 81, 97, 117], [17, 30, 15, 12, 2]), ([0, 16, 32, 48, 64, 80, 100, 119], [20, 0, 0, 2, 3]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([8, 17, 43, 51, 75, 83, 97, 114], [2, 0, 0, 1, 1]), ([7, 16, 38, 48, 69, 80, 96, 115], [16, 5, 6, 9, 1]), ([13, 17, 43, 51, 64, 80, 99, 117], [19, 1, 0, 1, 2]), ([6, 17, 43, 51, 75, 83, 102, 113], [23, 0, 0, 0, 0])], [([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([7, 16, 38, 48, 69, 80, 96, 115], [16, 5, 6, 9, 1]), ([13, 17, 43, 51, 64, 80, 99, 117], [19, 1, 0, 1, 2]), ([6, 17, 43, 51, 75, 83, 102, 113], [23, 0, 0, 0, 0]), ([4, 17, 40, 51, 66, 82, 108, 118], [12, 34, 56, 22, 3]), ([0, 16, 32, 48, 64, 80, 96], None), ([16, 32, 48, 64, 80, 96, 112, 0], None), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1])], [([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([4, 17, 40, 51, 66, 82, 108, 118], [12, 34, 56, 22, 3]), ([0, 16, 32, 48, 64, 80, 96], None), ([16, 32, 48, 64, 80, 96, 112, 0], None), ([3, 0, 16, 32, 48, 64, 80, 98, 112], [2, 0, 0, 2, 0]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1]), ([9, 16, 41, 48, 73, 80, 105, 112], [9, 9, 9, 11, 0])], [([0, 16, 32, 48, 64, 80, 96, 112], [0, 0, 0, 2, 0]), ([5, 17, 32, 48, 64, 80, 96, 114], [0, 0, 0, 23, 1]), ([4, 16, 35, 48, 66, 80, 97, 114], [1, 2, 3, 6, 1]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([3, 0, 16, 32, 48, 64, 80, 98, 112], [2, 0, 0, 2, 0]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1]), ([9, 16, 41, 48, 73, 80, 105, 112], [9, 9, 9, 11, 0])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("oracle %d" % i, 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| oracle 0 | [0, 0, 0, 2, 0] | [0, 0, 0, 2, 0] | Passed |
| oracle 1 | [0, 0, 0, 23, 1] | [0, 0, 0, 23, 1] | Passed |
| oracle 2 | [1, 2, 3, 6, 1] | [1, 2, 3, 6, 1] | Passed |
| oracle 3 | [17, 30, 15, 12, 2] | [17, 30, 15, 12, 2] | Passed |
| oracle 4 | [20, 0, 0, 2, 3] | [20, 0, 0, 2, 3] | Passed |
| oracle 5 | [24, 0, 0, 1, 0] | [0, 0, 0, 1, 0] | Failed |
| oracle 6 | [2, 0, 0, 1, 1] | [2, 0, 0, 1, 1] | Passed |
| oracle 7 | [24, 0, 0, 1, 1] | [0, 0, 0, 1, 1] | Failed |
SHA-256 / 7386f5a905c770de527a7371a142fc5a53e86f49f9d774f9a44556550ecc6079
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if not isinstance(x, list) or len(x) < 8:
return None
last8 = x[-8:]
if [b >> 4 for b in last8] != list(range(8)):
return None
nib = [b & 0x0F for b in last8]
frames = nib[0] | (nib[1] << 4)
secs = nib[2] | (nib[3] << 4)
mins = nib[4] | (nib[5] << 4)
hours = nib[6] | ((nib[7] & 0x1) << 4)
rate = (nib[7] >> 1) & 0x3
fps = [24, 25, 30, 30][rate]
frames += 2
secs += frames // fps
frames %= fps
mins += secs // 60
secs %= 60
hours = hours % 24 + mins // 60
mins %= 60
return [hours, mins, secs, frames, rate]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 16, 32, 48, 64, 80, 96, 112], [0, 0, 0, 2, 0]), ([5, 17, 32, 48, 64, 80, 96, 114], [0, 0, 0, 23, 1]), ([4, 16, 35, 48, 66, 80, 97, 114], [1, 2, 3, 6, 1]), ([10, 16, 47, 48, 78, 81, 97, 117], [17, 30, 15, 12, 2]), ([0, 16, 32, 48, 64, 80, 100, 119], [20, 0, 0, 2, 3]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([8, 17, 43, 51, 75, 83, 97, 114], [2, 0, 0, 1, 1]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1])], [([10, 16, 47, 48, 78, 81, 97, 117], [17, 30, 15, 12, 2]), ([0, 16, 32, 48, 64, 80, 100, 119], [20, 0, 0, 2, 3]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([8, 17, 43, 51, 75, 83, 97, 114], [2, 0, 0, 1, 1]), ([7, 16, 38, 48, 69, 80, 96, 115], [16, 5, 6, 9, 1]), ([13, 17, 43, 51, 64, 80, 99, 117], [19, 1, 0, 1, 2]), ([6, 17, 43, 51, 75, 83, 102, 113], [23, 0, 0, 0, 0])], [([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([7, 16, 38, 48, 69, 80, 96, 115], [16, 5, 6, 9, 1]), ([13, 17, 43, 51, 64, 80, 99, 117], [19, 1, 0, 1, 2]), ([6, 17, 43, 51, 75, 83, 102, 113], [23, 0, 0, 0, 0]), ([4, 17, 40, 51, 66, 82, 108, 118], [12, 34, 56, 22, 3]), ([0, 16, 32, 48, 64, 80, 96], None), ([16, 32, 48, 64, 80, 96, 112, 0], None), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1])], [([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([4, 17, 40, 51, 66, 82, 108, 118], [12, 34, 56, 22, 3]), ([0, 16, 32, 48, 64, 80, 96], None), ([16, 32, 48, 64, 80, 96, 112, 0], None), ([3, 0, 16, 32, 48, 64, 80, 98, 112], [2, 0, 0, 2, 0]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1]), ([9, 16, 41, 48, 73, 80, 105, 112], [9, 9, 9, 11, 0])], [([0, 16, 32, 48, 64, 80, 96, 112], [0, 0, 0, 2, 0]), ([5, 17, 32, 48, 64, 80, 96, 114], [0, 0, 0, 23, 1]), ([4, 16, 35, 48, 66, 80, 97, 114], [1, 2, 3, 6, 1]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([3, 0, 16, 32, 48, 64, 80, 98, 112], [2, 0, 0, 2, 0]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1]), ([9, 16, 41, 48, 73, 80, 105, 112], [9, 9, 9, 11, 0])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("oracle %d" % i, 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| oracle 0 | [0, 0, 0, 2, 0] | [0, 0, 0, 2, 0] | Passed |
| oracle 1 | [0, 0, 0, 23, 1] | [0, 0, 0, 23, 1] | Passed |
| oracle 2 | [1, 2, 3, 6, 1] | [1, 2, 3, 6, 1] | Passed |
| oracle 3 | [17, 30, 15, 12, 2] | [17, 30, 15, 12, 2] | Passed |
| oracle 4 | [20, 0, 0, 2, 3] | [20, 0, 0, 2, 3] | Passed |
| oracle 5 | [24, 0, 0, 1, 0] | [0, 0, 0, 1, 0] | Failed |
| oracle 6 | [2, 0, 0, 1, 1] | [2, 0, 0, 1, 1] | Passed |
| oracle 7 | [24, 0, 0, 1, 1] | [0, 0, 0, 1, 1] | Failed |
SHA-256 / 953c8faa1bdfd8db4e23a037c7c8ae470f426b1ae258cd4ba80f041ede1dc5e6
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if not isinstance(x, list) or len(x) < 8:
return None
last8 = x[-8:]
if [b >> 4 for b in last8] != list(range(8)):
return None
nib = [b & 0x0F for b in last8]
frames = nib[0] | (nib[1] << 4)
secs = nib[2] | (nib[3] << 4)
mins = nib[4] | (nib[5] << 4)
hours = nib[6] | ((nib[7] & 0x1) << 4)
rate = (nib[7] >> 1) & 0x3
fps = [24, 25, 30, 30][rate]
frames += 2
secs += frames // fps
frames %= fps
mins += secs // 60
secs %= 60
hours = (hours + mins // 60) % 24
mins %= 60
return [hours, mins, secs, frames, rate]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 16, 32, 48, 64, 80, 96, 112], [0, 0, 0, 2, 0]), ([5, 17, 32, 48, 64, 80, 96, 114], [0, 0, 0, 23, 1]), ([4, 16, 35, 48, 66, 80, 97, 114], [1, 2, 3, 6, 1]), ([10, 16, 47, 48, 78, 81, 97, 117], [17, 30, 15, 12, 2]), ([0, 16, 32, 48, 64, 80, 100, 119], [20, 0, 0, 2, 3]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([8, 17, 43, 51, 75, 83, 97, 114], [2, 0, 0, 1, 1]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1])], [([10, 16, 47, 48, 78, 81, 97, 117], [17, 30, 15, 12, 2]), ([0, 16, 32, 48, 64, 80, 100, 119], [20, 0, 0, 2, 3]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([8, 17, 43, 51, 75, 83, 97, 114], [2, 0, 0, 1, 1]), ([7, 16, 38, 48, 69, 80, 96, 115], [16, 5, 6, 9, 1]), ([13, 17, 43, 51, 64, 80, 99, 117], [19, 1, 0, 1, 2]), ([6, 17, 43, 51, 75, 83, 102, 113], [23, 0, 0, 0, 0])], [([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([7, 16, 38, 48, 69, 80, 96, 115], [16, 5, 6, 9, 1]), ([13, 17, 43, 51, 64, 80, 99, 117], [19, 1, 0, 1, 2]), ([6, 17, 43, 51, 75, 83, 102, 113], [23, 0, 0, 0, 0]), ([4, 17, 40, 51, 66, 82, 108, 118], [12, 34, 56, 22, 3]), ([0, 16, 32, 48, 64, 80, 96], None), ([16, 32, 48, 64, 80, 96, 112, 0], None), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1])], [([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([4, 17, 40, 51, 66, 82, 108, 118], [12, 34, 56, 22, 3]), ([0, 16, 32, 48, 64, 80, 96], None), ([16, 32, 48, 64, 80, 96, 112, 0], None), ([3, 0, 16, 32, 48, 64, 80, 98, 112], [2, 0, 0, 2, 0]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1]), ([9, 16, 41, 48, 73, 80, 105, 112], [9, 9, 9, 11, 0])], [([0, 16, 32, 48, 64, 80, 96, 112], [0, 0, 0, 2, 0]), ([5, 17, 32, 48, 64, 80, 96, 114], [0, 0, 0, 23, 1]), ([4, 16, 35, 48, 66, 80, 97, 114], [1, 2, 3, 6, 1]), ([7, 17, 43, 51, 75, 83, 103, 113], [0, 0, 0, 1, 0]), ([12, 17, 43, 51, 75, 83, 103, 119], [0, 0, 0, 0, 3]), ([3, 0, 16, 32, 48, 64, 80, 98, 112], [2, 0, 0, 2, 0]), ([8, 17, 43, 51, 75, 83, 103, 115], [0, 0, 0, 1, 1]), ([9, 16, 41, 48, 73, 80, 105, 112], [9, 9, 9, 11, 0])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("oracle %d" % i, 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| oracle 0 | [0, 0, 0, 2, 0] | [0, 0, 0, 2, 0] | Passed |
| oracle 1 | [0, 0, 0, 23, 1] | [0, 0, 0, 23, 1] | Passed |
| oracle 2 | [1, 2, 3, 6, 1] | [1, 2, 3, 6, 1] | Passed |
| oracle 3 | [17, 30, 15, 12, 2] | [17, 30, 15, 12, 2] | Passed |
| oracle 4 | [20, 0, 0, 2, 3] | [20, 0, 0, 2, 3] | Passed |
| oracle 5 | [0, 0, 0, 1, 0] | [0, 0, 0, 1, 0] | Passed |
| oracle 6 | [2, 0, 0, 1, 1] | [2, 0, 0, 1, 1] | Passed |
| oracle 7 | [0, 0, 0, 1, 1] | [0, 0, 0, 1, 1] | Passed |
SHA-256 / a09c79350477d9ab7e620d4870a9df6a92599aaf4bb0b9886934429153e14027
Verification & scope
A deterministic bounded teaching model with a stipulated toy contract; it is not a complete Standard MIDI File or MIDI 1.0/2.0 implementation. 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:50:06.385946+00:00.
Case digest / db54871cc5392b500f7dd6a44466e5c9845a6a640c60c4ad8b7da8ccdefe11a6