FAILURE MAP
← Case archive

FA-81726 / MIDI event timing / Open access

Active sensing timeout detection: silence after the last message never times out · case 01

When sensing stops and no further messages arrive, no timeout is reported before end_time.

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

ROOT CAUSE

The trailing gap between the last message and end_time is not checked.

VERIFIED REPAIR

Restore the end of stream check step so that it reads `if armed and end - last > 300: out.append(last + 300)`.

Unsuccessful approach: Reporting the timeout at end_time instead of last + 300 places it too late.

Case contract

Input [messages, end_time] where messages are time-ordered [ms, kind]. Monitoring is armed by a "sense" message. While armed, if more than 300 ms pass between any two consecutive messages (of any kind), a timeout is reported at previous message time + 300 and monitoring disarms until the next sense message. At end_time the same check applies to the last message. Return the list of timeout times.

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) != 2:
        return None
    msgs, end = x
    armed = False
    last = None
    out = []
    for t, m in msgs:
        if armed and t - last > 300:
            out.append(last + 300)
            armed = False
        if m == 'sense':
            armed = True
        last = t
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300])], [([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense']], 300], []), ([[[0, 'sense'], [320, 'note'], [650, 'note']], 660], [300]), ([[], 100], [])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense']], 300], []), ([[[0, 'sense'], [320, 'note'], [650, 'note']], 660], [300]), ([[], 100], []), ([[[0, 'sense'], [200, 'clock'], [600, 'note']], 600], [500]), ([[[100, 'sense'], [420, 'clock']], 430], [400])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense'], [200, 'clock'], [600, 'note']], 600], [500]), ([[[100, 'sense'], [420, 'clock']], 430], [400])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300])]]
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[][]Passed
oracle 1[300][300]Passed
oracle 2[][]Passed
oracle 3[][]Passed
oracle 4[][]Passed
oracle 5[][800]Failed
oracle 6[300][300]Passed
oracle 7[][300]Failed

SHA-256 / e7eda045b2e93d3251473c3db9b69f9d9f600fe876f1debc2d84e8a7730e2828

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) != 2:
        return None
    msgs, end = x
    armed = False
    last = None
    out = []
    for t, m in msgs:
        if armed and t - last > 300:
            out.append(last + 300)
            armed = False
        if m == 'sense':
            armed = True
        last = t
    if armed and end - last > 300:
        out.append(end)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300])], [([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense']], 300], []), ([[[0, 'sense'], [320, 'note'], [650, 'note']], 660], [300]), ([[], 100], [])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense']], 300], []), ([[[0, 'sense'], [320, 'note'], [650, 'note']], 660], [300]), ([[], 100], []), ([[[0, 'sense'], [200, 'clock'], [600, 'note']], 600], [500]), ([[[100, 'sense'], [420, 'clock']], 430], [400])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense'], [200, 'clock'], [600, 'note']], 600], [500]), ([[[100, 'sense'], [420, 'clock']], 430], [400])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300])]]
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[][]Passed
oracle 1[300][300]Passed
oracle 2[][]Passed
oracle 3[][]Passed
oracle 4[][]Passed
oracle 5[1000][800]Failed
oracle 6[300][300]Passed
oracle 7[301][300]Failed

SHA-256 / cbffdea0fa7d41a9beeed410ee534ec15ea7b0c7a7f65934afb27ddb44d7e738

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) != 2:
        return None
    msgs, end = x
    armed = False
    last = None
    out = []
    for t, m in msgs:
        if armed and t - last > 300:
            out.append(last + 300)
            armed = False
        if m == 'sense':
            armed = True
        last = t
    if armed and end - last > 300:
        out.append(last + 300)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300])], [([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense']], 300], []), ([[[0, 'sense'], [320, 'note'], [650, 'note']], 660], [300]), ([[], 100], [])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense']], 300], []), ([[[0, 'sense'], [320, 'note'], [650, 'note']], 660], [300]), ([[], 100], []), ([[[0, 'sense'], [200, 'clock'], [600, 'note']], 600], [500]), ([[[100, 'sense'], [420, 'clock']], 430], [400])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense']], 301], [300]), ([[[0, 'sense'], [200, 'clock'], [600, 'note']], 600], [500]), ([[[100, 'sense'], [420, 'clock']], 430], [400])], [([[[0, 'sense'], [200, 'sense'], [400, 'sense']], 500], []), ([[[0, 'sense'], [301, 'note']], 301], [300]), ([[[0, 'sense'], [300, 'note']], 300], []), ([[[0, 'note'], [1000, 'note']], 2000], []), ([[[0, 'sense'], [250, 'clock'], [500, 'clock'], [750, 'sense']], 800], []), ([[[0, 'sense'], [250, 'note'], [500, 'note']], 1000], [800]), ([[[0, 'sense'], [800, 'note'], [900, 'note'], [1300, 'sense']], 1400], [300]), ([[[0, 'sense']], 301], [300])]]
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[][]Passed
oracle 1[300][300]Passed
oracle 2[][]Passed
oracle 3[][]Passed
oracle 4[][]Passed
oracle 5[800][800]Passed
oracle 6[300][300]Passed
oracle 7[300][300]Passed

SHA-256 / 992cd5b31cca7bae4debc9904a2dc1e88e01e6d59438b80c0c733c2deffe2720

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

Case digest / ad3cfb295d7284bb06ee7bf725a63b2cfe33c2d8fdd7ffd223bd7d777569d5a3