FAILURE MAP
← Case archive

FA-81706 / MIDI event timing / Open access

Tick resolution conversion preserving note length: ratio applied upside down · case 01

Converting 480 ppq to 96 ppq multiplies ticks by five instead of dividing.

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

ROOT CAUSE

The scale factor uses source/target instead of target/source.

VERIFIED REPAIR

Restore the conversion direction step so that it reads `(2 * tick * dst + src) // (2 * src)`.

Unsuccessful approach: Using the target resolution as the rounding bias skews every rounded tick.

Case contract

Input [events, source_ppq, target_ppq] with events [tick, kind, note] in time order. Each tick maps to tick*target/source rounded half up. A note-off (matched FIFO to the earliest open note-on of the same note) whose original length was positive but whose converted tick is not after its note-on is moved to note-on + 1. Invalid resolutions return 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) != 3:
        return None
    events, src, dst = x
    if src <= 0 or dst <= 0:
        return None
    out = []
    open_on = {}
    for tick, kind, note in events:
        t = (2 * tick * src + dst) // (2 * dst)
        if kind == 'on':
            open_on.setdefault(note, []).append((tick, t))
        elif open_on.get(note):
            otick, ot = open_on[note].pop(0)
            if tick > otick and t <= ot:
                t = ot + 1
        out.append([t, kind, note])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[[0, 'on', 60], [480, 'off', 60]], 480, 96], [[0, 'on', 60], [96, 'off', 60]]), ([[[0, 'on', 60], [1, 'off', 60]], 480, 96], [[0, 'on', 60], [1, 'off', 60]]), ([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [0, 'off', 60]], 480, 96], [[0, 'on', 60], [0, 'off', 60]]), ([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60]], 0, 96], None)], [([[[0, 'on', 60], [1, 'off', 60]], 480, 96], [[0, 'on', 60], [1, 'off', 60]]), ([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]])], [([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]]), ([[[0, 'on', 60], [5, 'on', 60], [6, 'off', 60], [40, 'off', 60]], 10, 1], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [4, 'off', 60]]), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]])], [([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]]), ([[[0, 'on', 60], [5, 'on', 60], [6, 'off', 60], [40, 'off', 60]], 10, 1], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [4, 'off', 60]]), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]]), ([[[3, 'on', 64], [5, 'off', 64]], 6, 4], [[2, 'on', 64], [3, 'off', 64]]), ([[[0, 'on', 60], [1, 'on', 60], [2, 'off', 60], [3, 'off', 60]], 10, 1], [[0, 'on', 60], [0, 'on', 60], [1, 'off', 60], [1, 'off', 60]])], [([[[0, 'on', 60], [480, 'off', 60]], 480, 96], [[0, 'on', 60], [96, 'off', 60]]), ([[[0, 'on', 60], [0, 'off', 60]], 480, 96], [[0, 'on', 60], [0, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60]], 0, 96], None), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]]), ([[[3, 'on', 64], [5, 'off', 64]], 6, 4], [[2, 'on', 64], [3, 'off', 64]]), ([[[0, 'on', 60], [1, 'on', 60], [2, 'off', 60], [3, 'off', 60]], 10, 1], [[0, 'on', 60], [0, 'on', 60], [1, 'off', 60], [1, 'off', 60]])]]
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 fixtureActualExpectedOutcome
oracle 0[[0, 'on', 60], [2400, 'off', 60]][[0, 'on', 60], [96, 'off', 60]]Failed
oracle 1[[0, 'on', 60], [5, 'off', 60]][[0, 'on', 60], [1, 'off', 60]]Failed
oracle 2[[2, 'on', 60], [6, 'off', 60]][[1, 'on', 60], [2, 'off', 60]]Failed
oracle 3[[0, 'on', 60], [0, 'off', 60]][[0, 'on', 60], [0, 'off', 60]]Passed
oracle 4[[50, 'on', 60], [70, 'off', 60]][[1, 'on', 60], [2, 'off', 60]]Failed
oracle 5[[2, 'on', 60]][[1, 'on', 60]]Failed
oracle 6[[6, 'on', 60]][[2, 'on', 60]]Failed
oracle 7NoneNonePassed

SHA-256 / 7766d3e4814321e6266b764f439306da143d4984ae463bb63d21232632276d31

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) != 3:
        return None
    events, src, dst = x
    if src <= 0 or dst <= 0:
        return None
    out = []
    open_on = {}
    for tick, kind, note in events:
        t = (2 * tick * dst + dst) // (2 * src)
        if kind == 'on':
            open_on.setdefault(note, []).append((tick, t))
        elif open_on.get(note):
            otick, ot = open_on[note].pop(0)
            if tick > otick and t <= ot:
                t = ot + 1
        out.append([t, kind, note])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[[0, 'on', 60], [480, 'off', 60]], 480, 96], [[0, 'on', 60], [96, 'off', 60]]), ([[[0, 'on', 60], [1, 'off', 60]], 480, 96], [[0, 'on', 60], [1, 'off', 60]]), ([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [0, 'off', 60]], 480, 96], [[0, 'on', 60], [0, 'off', 60]]), ([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60]], 0, 96], None)], [([[[0, 'on', 60], [1, 'off', 60]], 480, 96], [[0, 'on', 60], [1, 'off', 60]]), ([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]])], [([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]]), ([[[0, 'on', 60], [5, 'on', 60], [6, 'off', 60], [40, 'off', 60]], 10, 1], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [4, 'off', 60]]), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]])], [([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]]), ([[[0, 'on', 60], [5, 'on', 60], [6, 'off', 60], [40, 'off', 60]], 10, 1], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [4, 'off', 60]]), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]]), ([[[3, 'on', 64], [5, 'off', 64]], 6, 4], [[2, 'on', 64], [3, 'off', 64]]), ([[[0, 'on', 60], [1, 'on', 60], [2, 'off', 60], [3, 'off', 60]], 10, 1], [[0, 'on', 60], [0, 'on', 60], [1, 'off', 60], [1, 'off', 60]])], [([[[0, 'on', 60], [480, 'off', 60]], 480, 96], [[0, 'on', 60], [96, 'off', 60]]), ([[[0, 'on', 60], [0, 'off', 60]], 480, 96], [[0, 'on', 60], [0, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60]], 0, 96], None), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]]), ([[[3, 'on', 64], [5, 'off', 64]], 6, 4], [[2, 'on', 64], [3, 'off', 64]]), ([[[0, 'on', 60], [1, 'on', 60], [2, 'off', 60], [3, 'off', 60]], 10, 1], [[0, 'on', 60], [0, 'on', 60], [1, 'off', 60], [1, 'off', 60]])]]
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 fixtureActualExpectedOutcome
oracle 0[[0, 'on', 60], [96, 'off', 60]][[0, 'on', 60], [96, 'off', 60]]Passed
oracle 1[[0, 'on', 60], [1, 'off', 60]][[0, 'on', 60], [1, 'off', 60]]Passed
oracle 2[[0, 'on', 60], [1, 'off', 60]][[1, 'on', 60], [2, 'off', 60]]Failed
oracle 3[[0, 'on', 60], [0, 'off', 60]][[0, 'on', 60], [0, 'off', 60]]Passed
oracle 4[[0, 'on', 60], [1, 'off', 60]][[1, 'on', 60], [2, 'off', 60]]Failed
oracle 5[[0, 'on', 60]][[1, 'on', 60]]Failed
oracle 6[[1, 'on', 60]][[2, 'on', 60]]Failed
oracle 7NoneNonePassed

SHA-256 / 73e1cd7d625c389f5d7b262cd87280da2571d8a31495aa05621b9c43acaf171a

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) != 3:
        return None
    events, src, dst = x
    if src <= 0 or dst <= 0:
        return None
    out = []
    open_on = {}
    for tick, kind, note in events:
        t = (2 * tick * dst + src) // (2 * src)
        if kind == 'on':
            open_on.setdefault(note, []).append((tick, t))
        elif open_on.get(note):
            otick, ot = open_on[note].pop(0)
            if tick > otick and t <= ot:
                t = ot + 1
        out.append([t, kind, note])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[[0, 'on', 60], [480, 'off', 60]], 480, 96], [[0, 'on', 60], [96, 'off', 60]]), ([[[0, 'on', 60], [1, 'off', 60]], 480, 96], [[0, 'on', 60], [1, 'off', 60]]), ([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [0, 'off', 60]], 480, 96], [[0, 'on', 60], [0, 'off', 60]]), ([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60]], 0, 96], None)], [([[[0, 'on', 60], [1, 'off', 60]], 480, 96], [[0, 'on', 60], [1, 'off', 60]]), ([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]])], [([[[1, 'on', 60], [3, 'off', 60]], 2, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]]), ([[[0, 'on', 60], [5, 'on', 60], [6, 'off', 60], [40, 'off', 60]], 10, 1], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [4, 'off', 60]]), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]])], [([[[5, 'on', 60], [7, 'off', 60]], 10, 1], [[1, 'on', 60], [2, 'off', 60]]), ([[[3, 'on', 60]], 2, 1], [[2, 'on', 60]]), ([[[0, 'on', 60], [100, 'off', 60]], 96, 480], [[0, 'on', 60], [500, 'off', 60]]), ([[[7, 'on', 62], [250, 'off', 62]], 480, 96], [[1, 'on', 62], [50, 'off', 62]]), ([[[0, 'on', 60], [5, 'on', 60], [6, 'off', 60], [40, 'off', 60]], 10, 1], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [4, 'off', 60]]), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]]), ([[[3, 'on', 64], [5, 'off', 64]], 6, 4], [[2, 'on', 64], [3, 'off', 64]]), ([[[0, 'on', 60], [1, 'on', 60], [2, 'off', 60], [3, 'off', 60]], 10, 1], [[0, 'on', 60], [0, 'on', 60], [1, 'off', 60], [1, 'off', 60]])], [([[[0, 'on', 60], [480, 'off', 60]], 480, 96], [[0, 'on', 60], [96, 'off', 60]]), ([[[0, 'on', 60], [0, 'off', 60]], 480, 96], [[0, 'on', 60], [0, 'off', 60]]), ([[[1, 'on', 60]], 2, 1], [[1, 'on', 60]]), ([[[0, 'on', 60], [2, 'on', 60], [3, 'off', 60], [9, 'off', 60]], 8, 2], [[0, 'on', 60], [1, 'on', 60], [1, 'off', 60], [2, 'off', 60]]), ([[[0, 'on', 60]], 0, 96], None), ([[[12, 'on', 61], [13, 'off', 61]], 24, 1], [[1, 'on', 61], [2, 'off', 61]]), ([[[3, 'on', 64], [5, 'off', 64]], 6, 4], [[2, 'on', 64], [3, 'off', 64]]), ([[[0, 'on', 60], [1, 'on', 60], [2, 'off', 60], [3, 'off', 60]], 10, 1], [[0, 'on', 60], [0, 'on', 60], [1, 'off', 60], [1, 'off', 60]])]]
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 fixtureActualExpectedOutcome
oracle 0[[0, 'on', 60], [96, 'off', 60]][[0, 'on', 60], [96, 'off', 60]]Passed
oracle 1[[0, 'on', 60], [1, 'off', 60]][[0, 'on', 60], [1, 'off', 60]]Passed
oracle 2[[1, 'on', 60], [2, 'off', 60]][[1, 'on', 60], [2, 'off', 60]]Passed
oracle 3[[0, 'on', 60], [0, 'off', 60]][[0, 'on', 60], [0, 'off', 60]]Passed
oracle 4[[1, 'on', 60], [2, 'off', 60]][[1, 'on', 60], [2, 'off', 60]]Passed
oracle 5[[1, 'on', 60]][[1, 'on', 60]]Passed
oracle 6[[2, 'on', 60]][[2, 'on', 60]]Passed
oracle 7NoneNonePassed

SHA-256 / 155eb0553d4d9a1ed8841da7b8d8449385dc5cd4d1cb836ec5735325731b344a

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

Case digest / 632846604274959963d9f4bb51205ea2594931139018884da1ed3b3141f72924