FAILURE MAP
← Case archive

FA-67971 / Traffic signal timing plans / Open access

Actuated phase gap-out and max-out: the max timer runs from the start of green · case 01

Actuated phase gap-out and max-out returns a wrong result when the max timer runs from the start of green.

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

ROOT CAUSE

Max green is timed from green start instead of from the conflicting call, cutting phases short when the call arrives late.

VERIFIED REPAIR

Restore the max timer start rule so that the step reads `max_end = tc + M`.

Unsuccessful approach: Subtracting min green from the call-based timer is still not the stipulated max-out instant.

Case contract

Input {min_green, gap, max_green, actuations: integer seconds since green start (any order), conflict_call: seconds or null}. Each actuation at a keeps the phase eligible until a+gap; an actuation exactly at expiry extends; actuations during min green always extend. Gap-out time = max(min_green, final expiry). With no conflicting call return ['rest', gap time]. The max timer starts at the call (a call before green start counts as 0); max-out at call+max_green. If gap time <= max-out the phase ends by 'gap-out' at max(gap time, call), else by 'max-out'.

Why this case matters

Signal timing arithmetic is exact and integer or rational; a wrong rule silently produces unsafe or inefficient timing plans.

1 / The failure

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

N = 1
observations = []
def solve(x):
    m, p, M = x['min_green'], x['gap'], x['max_green']
    exp = 0
    for a in sorted(x['actuations']):
        if a > exp and a > m:
            break
        exp = max(exp, a + p)
    gap_end = max(m, exp)
    tc = x['conflict_call']
    if tc is None:
        return ['rest', gap_end]
    tc = max(tc, 0)
    max_end = M
    if gap_end <= max_end:
        return ['gap-out', max(gap_end, tc)]
    return ['max-out', max_end]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'min_green': 4, 'gap': 4, 'max_green': 38, 'actuations': [2, 5, 6, 7, 8, 14, 16, 20, 23, 24, 26, 30, 32, 35, 41, 44, 49, 51, 54, 56, 59], 'conflict_call': 15}, ['gap-out', 15]), ({'min_green': 7, 'gap': 5, 'max_green': 40, 'actuations': [2, 3, 5, 7, 10, 12, 13, 14, 15, 18, 19, 20, 25, 29, 32, 33, 35, 37, 39, 44, 45, 46, 51, 52, 54, 57], 'conflict_call': 34}, ['gap-out', 62]), ({'min_green': 8, 'gap': 5, 'max_green': 37, 'actuations': [2, 6, 8, 10, 11, 12, 14, 16, 17, 18, 19, 24, 25, 27, 28, 30, 31, 35, 37, 39, 43, 45, 46, 47, 48, 49, 50, 51, 55, 57], 'conflict_call': 20}, ['max-out', 57]), ({'min_green': 7, 'gap': 3, 'max_green': 15, 'actuations': [46, 42, 45, 38, 32, 27, 3, 9, 1, 15, 24, 16, 56, 2, 22, 40, 20, 14, 7, 28, 26, 8, 55, 58, 29, 5, 48, 59, 34, 35, 11], 'conflict_call': 23}, ['gap-out', 23]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 5, 'gap': 3, 'max_green': 20, 'actuations': [1, 4, 7, 10, 13], 'conflict_call': 2}, ['gap-out', 16]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 9, 'gap': 4, 'max_green': 38, 'actuations': [13, 39, 8, 1, 36, 52, 20, 18, 53, 9, 45, 56, 55, 17, 2, 58, 23, 42, 26, 24, 14, 7, 34, 11, 33, 30, 51, 54, 28, 35, 50], 'conflict_call': 27}, ['gap-out', 49])], [({'min_green': 6, 'gap': 3, 'max_green': 29, 'actuations': [0, 2, 4, 5, 8, 9, 10, 13, 14, 19, 21, 22, 27, 28, 30, 31, 33, 35, 38, 39, 40, 42, 44, 46, 47, 48, 49, 51, 54, 55, 56, 57, 59], 'conflict_call': 16}, ['gap-out', 17]), ({'min_green': 12, 'gap': 3, 'max_green': 5, 'actuations': [1], 'conflict_call': 2}, ['max-out', 7]), ({'min_green': 4, 'gap': 2, 'max_green': 38, 'actuations': [0, 5, 6, 7, 10, 11, 16, 17, 20, 21, 24, 27, 29, 31, 33, 34, 35, 39, 41, 43, 46, 47, 48, 49, 52, 55, 57, 58], 'conflict_call': 11}, ['gap-out', 11]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 4, 'gap': 5, 'max_green': 23, 'actuations': [1, 3, 6, 8, 11, 12, 15, 20, 25, 27, 28, 29, 31, 35, 37, 38, 41, 42, 43, 44, 50, 57], 'conflict_call': 10}, ['max-out', 33]), ({'min_green': 10, 'gap': 5, 'max_green': 25, 'actuations': [1, 3, 7, 9, 10, 14, 16, 18, 19, 23, 24, 26, 27, 28, 30, 34, 35, 37, 38, 42, 43, 44, 46, 49, 54, 59], 'conflict_call': 20}, ['max-out', 45]), ({'min_green': 10, 'gap': 3, 'max_green': 43, 'actuations': [0, 4, 7, 12, 14, 21, 24, 25, 41, 44, 47, 59], 'conflict_call': 10}, ['gap-out', 10]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3])], [({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15]), ({'min_green': 4, 'gap': 3, 'max_green': 31, 'actuations': [7, 8, 11, 14, 15, 21, 27, 32, 37, 46, 52, 57], 'conflict_call': None}, ['rest', 4]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 5, 'gap': 5, 'max_green': 22, 'actuations': [1, 3, 5, 9, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25, 27, 29, 31, 32, 34, 36, 37, 38, 40, 47, 49, 52, 55, 56, 57, 58, 59], 'conflict_call': 32}, ['gap-out', 45]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 5, 'gap': 4, 'max_green': 44, 'actuations': [1, 3, 4, 5, 6, 7, 10, 16, 17, 19, 20, 21, 25, 26, 28, 29, 32, 33, 34, 35, 38, 39, 41, 43, 44, 47, 49, 52, 56, 57, 58, 59], 'conflict_call': None}, ['rest', 14]), ({'min_green': 8, 'gap': 3, 'max_green': 29, 'actuations': [0, 2, 3, 6, 9, 11, 12, 14, 15, 17, 18, 19, 21, 22, 25, 27, 30, 31, 36, 38, 41, 42, 43, 45, 48, 52, 53, 55, 57, 59], 'conflict_call': 31}, ['gap-out', 34]), ({'min_green': 4, 'gap': 5, 'max_green': 45, 'actuations': [2, 3, 4, 5, 6, 7, 11, 12, 15, 17, 18, 20, 21, 22, 23, 25, 28, 29, 34, 35, 36, 37, 39, 41, 42, 49, 50, 51, 55, 56], 'conflict_call': 29}, ['gap-out', 47])], [({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15]), ({'min_green': 4, 'gap': 3, 'max_green': 33, 'actuations': [13, 36, 51, 10, 4, 20, 44, 6, 49, 32, 40, 7, 47, 14, 21, 31, 29, 8, 9, 56, 53, 50, 38, 5, 24, 27, 12, 17, 45, 52, 54], 'conflict_call': -6}, ['max-out', 33]), ({'min_green': 9, 'gap': 5, 'max_green': 34, 'actuations': [0, 2, 8, 9, 10, 11, 14, 16, 18, 23, 27, 29, 30, 31, 36, 38, 39, 40, 48, 50, 53, 55, 56], 'conflict_call': 33}, ['gap-out', 45]), ({'min_green': 10, 'gap': 5, 'max_green': 28, 'actuations': [13, 1, 18, 8, 59, 45, 3, 31, 4, 36, 12, 50, 6, 46, 7, 34, 40, 54, 19, 53, 48, 20, 52, 25, 57, 47, 5, 24, 16], 'conflict_call': 31}, ['gap-out', 31]), ({'min_green': 7, 'gap': 2, 'max_green': 31, 'actuations': [0, 2, 3, 7, 9, 19, 21, 23, 25, 28, 30, 38, 41, 43, 44, 48, 49, 51, 53, 56, 57], 'conflict_call': None}, ['rest', 11]), ({'min_green': 8, 'gap': 4, 'max_green': 44, 'actuations': [0, 2, 4, 6, 9, 12, 13, 15, 17, 18, 19, 23, 26, 29, 30, 32, 33, 35, 36, 38, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 55, 56], 'conflict_call': 15}, ['max-out', 59])], [({'min_green': 7, 'gap': 5, 'max_green': 38, 'actuations': [1, 3, 5, 6, 8, 9, 10, 11, 12, 13, 16, 18, 21, 23, 25, 26, 29, 31, 33, 34, 37, 38, 40, 41, 43, 44, 46, 48, 53, 54, 56, 57, 59], 'conflict_call': 12}, ['max-out', 50]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 7, 'gap': 3, 'max_green': 19, 'actuations': [0, 2, 5, 6, 7, 12, 15, 17, 21, 24, 25, 26, 27, 28, 29, 33, 34, 36, 38, 39, 40, 41, 44, 45, 47, 49, 50, 53, 54, 56], 'conflict_call': 0}, ['gap-out', 10]), ({'min_green': 6, 'gap': 2, 'max_green': 12, 'actuations': [1, 3, 5, 7, 9, 11, 13], 'conflict_call': 3}, ['gap-out', 15]), ({'min_green': 5, 'gap': 4, 'max_green': 41, 'actuations': [1, 2, 4, 6, 7, 8, 10, 13, 14, 17, 18, 19, 20, 21, 25, 26, 27, 28, 32, 35, 37, 38, 39, 40, 41, 43, 45, 47, 48, 50, 54, 55, 59], 'conflict_call': 31}, ['gap-out', 63]), ({'min_green': 10, 'gap': 4, 'max_green': 21, 'actuations': [5, 30, 36, 38, 46, 55], 'conflict_call': 34}, ['gap-out', 34]), ({'min_green': 4, 'gap': 5, 'max_green': 28, 'actuations': [2, 7, 57], 'conflict_call': None}, ['rest', 12]), ({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing 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
timing oracle 0['gap-out', 15]['gap-out', 15]Passed
timing oracle 1['max-out', 40]['gap-out', 62]Failed
timing oracle 2['max-out', 37]['max-out', 57]Failed
timing oracle 3['max-out', 15]['gap-out', 23]Failed
timing oracle 4['max-out', 3]['max-out', 3]Passed
timing oracle 5['gap-out', 16]['gap-out', 16]Passed
timing oracle 6['gap-out', 20]['gap-out', 20]Passed
timing oracle 7['max-out', 38]['gap-out', 49]Failed

SHA-256 / c52f611598d42d39a2a981c89d329d08c7d8e0c8f46f2ca793b4fde89c55f1ba

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    m, p, M = x['min_green'], x['gap'], x['max_green']
    exp = 0
    for a in sorted(x['actuations']):
        if a > exp and a > m:
            break
        exp = max(exp, a + p)
    gap_end = max(m, exp)
    tc = x['conflict_call']
    if tc is None:
        return ['rest', gap_end]
    tc = max(tc, 0)
    max_end = tc + M - m
    if gap_end <= max_end:
        return ['gap-out', max(gap_end, tc)]
    return ['max-out', max_end]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'min_green': 4, 'gap': 4, 'max_green': 38, 'actuations': [2, 5, 6, 7, 8, 14, 16, 20, 23, 24, 26, 30, 32, 35, 41, 44, 49, 51, 54, 56, 59], 'conflict_call': 15}, ['gap-out', 15]), ({'min_green': 7, 'gap': 5, 'max_green': 40, 'actuations': [2, 3, 5, 7, 10, 12, 13, 14, 15, 18, 19, 20, 25, 29, 32, 33, 35, 37, 39, 44, 45, 46, 51, 52, 54, 57], 'conflict_call': 34}, ['gap-out', 62]), ({'min_green': 8, 'gap': 5, 'max_green': 37, 'actuations': [2, 6, 8, 10, 11, 12, 14, 16, 17, 18, 19, 24, 25, 27, 28, 30, 31, 35, 37, 39, 43, 45, 46, 47, 48, 49, 50, 51, 55, 57], 'conflict_call': 20}, ['max-out', 57]), ({'min_green': 7, 'gap': 3, 'max_green': 15, 'actuations': [46, 42, 45, 38, 32, 27, 3, 9, 1, 15, 24, 16, 56, 2, 22, 40, 20, 14, 7, 28, 26, 8, 55, 58, 29, 5, 48, 59, 34, 35, 11], 'conflict_call': 23}, ['gap-out', 23]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 5, 'gap': 3, 'max_green': 20, 'actuations': [1, 4, 7, 10, 13], 'conflict_call': 2}, ['gap-out', 16]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 9, 'gap': 4, 'max_green': 38, 'actuations': [13, 39, 8, 1, 36, 52, 20, 18, 53, 9, 45, 56, 55, 17, 2, 58, 23, 42, 26, 24, 14, 7, 34, 11, 33, 30, 51, 54, 28, 35, 50], 'conflict_call': 27}, ['gap-out', 49])], [({'min_green': 6, 'gap': 3, 'max_green': 29, 'actuations': [0, 2, 4, 5, 8, 9, 10, 13, 14, 19, 21, 22, 27, 28, 30, 31, 33, 35, 38, 39, 40, 42, 44, 46, 47, 48, 49, 51, 54, 55, 56, 57, 59], 'conflict_call': 16}, ['gap-out', 17]), ({'min_green': 12, 'gap': 3, 'max_green': 5, 'actuations': [1], 'conflict_call': 2}, ['max-out', 7]), ({'min_green': 4, 'gap': 2, 'max_green': 38, 'actuations': [0, 5, 6, 7, 10, 11, 16, 17, 20, 21, 24, 27, 29, 31, 33, 34, 35, 39, 41, 43, 46, 47, 48, 49, 52, 55, 57, 58], 'conflict_call': 11}, ['gap-out', 11]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 4, 'gap': 5, 'max_green': 23, 'actuations': [1, 3, 6, 8, 11, 12, 15, 20, 25, 27, 28, 29, 31, 35, 37, 38, 41, 42, 43, 44, 50, 57], 'conflict_call': 10}, ['max-out', 33]), ({'min_green': 10, 'gap': 5, 'max_green': 25, 'actuations': [1, 3, 7, 9, 10, 14, 16, 18, 19, 23, 24, 26, 27, 28, 30, 34, 35, 37, 38, 42, 43, 44, 46, 49, 54, 59], 'conflict_call': 20}, ['max-out', 45]), ({'min_green': 10, 'gap': 3, 'max_green': 43, 'actuations': [0, 4, 7, 12, 14, 21, 24, 25, 41, 44, 47, 59], 'conflict_call': 10}, ['gap-out', 10]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3])], [({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15]), ({'min_green': 4, 'gap': 3, 'max_green': 31, 'actuations': [7, 8, 11, 14, 15, 21, 27, 32, 37, 46, 52, 57], 'conflict_call': None}, ['rest', 4]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 5, 'gap': 5, 'max_green': 22, 'actuations': [1, 3, 5, 9, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25, 27, 29, 31, 32, 34, 36, 37, 38, 40, 47, 49, 52, 55, 56, 57, 58, 59], 'conflict_call': 32}, ['gap-out', 45]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 5, 'gap': 4, 'max_green': 44, 'actuations': [1, 3, 4, 5, 6, 7, 10, 16, 17, 19, 20, 21, 25, 26, 28, 29, 32, 33, 34, 35, 38, 39, 41, 43, 44, 47, 49, 52, 56, 57, 58, 59], 'conflict_call': None}, ['rest', 14]), ({'min_green': 8, 'gap': 3, 'max_green': 29, 'actuations': [0, 2, 3, 6, 9, 11, 12, 14, 15, 17, 18, 19, 21, 22, 25, 27, 30, 31, 36, 38, 41, 42, 43, 45, 48, 52, 53, 55, 57, 59], 'conflict_call': 31}, ['gap-out', 34]), ({'min_green': 4, 'gap': 5, 'max_green': 45, 'actuations': [2, 3, 4, 5, 6, 7, 11, 12, 15, 17, 18, 20, 21, 22, 23, 25, 28, 29, 34, 35, 36, 37, 39, 41, 42, 49, 50, 51, 55, 56], 'conflict_call': 29}, ['gap-out', 47])], [({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15]), ({'min_green': 4, 'gap': 3, 'max_green': 33, 'actuations': [13, 36, 51, 10, 4, 20, 44, 6, 49, 32, 40, 7, 47, 14, 21, 31, 29, 8, 9, 56, 53, 50, 38, 5, 24, 27, 12, 17, 45, 52, 54], 'conflict_call': -6}, ['max-out', 33]), ({'min_green': 9, 'gap': 5, 'max_green': 34, 'actuations': [0, 2, 8, 9, 10, 11, 14, 16, 18, 23, 27, 29, 30, 31, 36, 38, 39, 40, 48, 50, 53, 55, 56], 'conflict_call': 33}, ['gap-out', 45]), ({'min_green': 10, 'gap': 5, 'max_green': 28, 'actuations': [13, 1, 18, 8, 59, 45, 3, 31, 4, 36, 12, 50, 6, 46, 7, 34, 40, 54, 19, 53, 48, 20, 52, 25, 57, 47, 5, 24, 16], 'conflict_call': 31}, ['gap-out', 31]), ({'min_green': 7, 'gap': 2, 'max_green': 31, 'actuations': [0, 2, 3, 7, 9, 19, 21, 23, 25, 28, 30, 38, 41, 43, 44, 48, 49, 51, 53, 56, 57], 'conflict_call': None}, ['rest', 11]), ({'min_green': 8, 'gap': 4, 'max_green': 44, 'actuations': [0, 2, 4, 6, 9, 12, 13, 15, 17, 18, 19, 23, 26, 29, 30, 32, 33, 35, 36, 38, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 55, 56], 'conflict_call': 15}, ['max-out', 59])], [({'min_green': 7, 'gap': 5, 'max_green': 38, 'actuations': [1, 3, 5, 6, 8, 9, 10, 11, 12, 13, 16, 18, 21, 23, 25, 26, 29, 31, 33, 34, 37, 38, 40, 41, 43, 44, 46, 48, 53, 54, 56, 57, 59], 'conflict_call': 12}, ['max-out', 50]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 7, 'gap': 3, 'max_green': 19, 'actuations': [0, 2, 5, 6, 7, 12, 15, 17, 21, 24, 25, 26, 27, 28, 29, 33, 34, 36, 38, 39, 40, 41, 44, 45, 47, 49, 50, 53, 54, 56], 'conflict_call': 0}, ['gap-out', 10]), ({'min_green': 6, 'gap': 2, 'max_green': 12, 'actuations': [1, 3, 5, 7, 9, 11, 13], 'conflict_call': 3}, ['gap-out', 15]), ({'min_green': 5, 'gap': 4, 'max_green': 41, 'actuations': [1, 2, 4, 6, 7, 8, 10, 13, 14, 17, 18, 19, 20, 21, 25, 26, 27, 28, 32, 35, 37, 38, 39, 40, 41, 43, 45, 47, 48, 50, 54, 55, 59], 'conflict_call': 31}, ['gap-out', 63]), ({'min_green': 10, 'gap': 4, 'max_green': 21, 'actuations': [5, 30, 36, 38, 46, 55], 'conflict_call': 34}, ['gap-out', 34]), ({'min_green': 4, 'gap': 5, 'max_green': 28, 'actuations': [2, 7, 57], 'conflict_call': None}, ['rest', 12]), ({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing 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
timing oracle 0['gap-out', 15]['gap-out', 15]Passed
timing oracle 1['gap-out', 62]['gap-out', 62]Passed
timing oracle 2['max-out', 49]['max-out', 57]Failed
timing oracle 3['gap-out', 23]['gap-out', 23]Passed
timing oracle 4['max-out', -7]['max-out', 3]Failed
timing oracle 5['gap-out', 16]['gap-out', 16]Passed
timing oracle 6['gap-out', 20]['gap-out', 20]Passed
timing oracle 7['gap-out', 49]['gap-out', 49]Passed

SHA-256 / 8aed73e3405174c22fe6d63ec6799029c02a1b6a1b909485513638fe471dcf6f

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    m, p, M = x['min_green'], x['gap'], x['max_green']
    exp = 0
    for a in sorted(x['actuations']):
        if a > exp and a > m:
            break
        exp = max(exp, a + p)
    gap_end = max(m, exp)
    tc = x['conflict_call']
    if tc is None:
        return ['rest', gap_end]
    tc = max(tc, 0)
    max_end = tc + M
    if gap_end <= max_end:
        return ['gap-out', max(gap_end, tc)]
    return ['max-out', max_end]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'min_green': 4, 'gap': 4, 'max_green': 38, 'actuations': [2, 5, 6, 7, 8, 14, 16, 20, 23, 24, 26, 30, 32, 35, 41, 44, 49, 51, 54, 56, 59], 'conflict_call': 15}, ['gap-out', 15]), ({'min_green': 7, 'gap': 5, 'max_green': 40, 'actuations': [2, 3, 5, 7, 10, 12, 13, 14, 15, 18, 19, 20, 25, 29, 32, 33, 35, 37, 39, 44, 45, 46, 51, 52, 54, 57], 'conflict_call': 34}, ['gap-out', 62]), ({'min_green': 8, 'gap': 5, 'max_green': 37, 'actuations': [2, 6, 8, 10, 11, 12, 14, 16, 17, 18, 19, 24, 25, 27, 28, 30, 31, 35, 37, 39, 43, 45, 46, 47, 48, 49, 50, 51, 55, 57], 'conflict_call': 20}, ['max-out', 57]), ({'min_green': 7, 'gap': 3, 'max_green': 15, 'actuations': [46, 42, 45, 38, 32, 27, 3, 9, 1, 15, 24, 16, 56, 2, 22, 40, 20, 14, 7, 28, 26, 8, 55, 58, 29, 5, 48, 59, 34, 35, 11], 'conflict_call': 23}, ['gap-out', 23]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 5, 'gap': 3, 'max_green': 20, 'actuations': [1, 4, 7, 10, 13], 'conflict_call': 2}, ['gap-out', 16]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 9, 'gap': 4, 'max_green': 38, 'actuations': [13, 39, 8, 1, 36, 52, 20, 18, 53, 9, 45, 56, 55, 17, 2, 58, 23, 42, 26, 24, 14, 7, 34, 11, 33, 30, 51, 54, 28, 35, 50], 'conflict_call': 27}, ['gap-out', 49])], [({'min_green': 6, 'gap': 3, 'max_green': 29, 'actuations': [0, 2, 4, 5, 8, 9, 10, 13, 14, 19, 21, 22, 27, 28, 30, 31, 33, 35, 38, 39, 40, 42, 44, 46, 47, 48, 49, 51, 54, 55, 56, 57, 59], 'conflict_call': 16}, ['gap-out', 17]), ({'min_green': 12, 'gap': 3, 'max_green': 5, 'actuations': [1], 'conflict_call': 2}, ['max-out', 7]), ({'min_green': 4, 'gap': 2, 'max_green': 38, 'actuations': [0, 5, 6, 7, 10, 11, 16, 17, 20, 21, 24, 27, 29, 31, 33, 34, 35, 39, 41, 43, 46, 47, 48, 49, 52, 55, 57, 58], 'conflict_call': 11}, ['gap-out', 11]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 4, 'gap': 5, 'max_green': 23, 'actuations': [1, 3, 6, 8, 11, 12, 15, 20, 25, 27, 28, 29, 31, 35, 37, 38, 41, 42, 43, 44, 50, 57], 'conflict_call': 10}, ['max-out', 33]), ({'min_green': 10, 'gap': 5, 'max_green': 25, 'actuations': [1, 3, 7, 9, 10, 14, 16, 18, 19, 23, 24, 26, 27, 28, 30, 34, 35, 37, 38, 42, 43, 44, 46, 49, 54, 59], 'conflict_call': 20}, ['max-out', 45]), ({'min_green': 10, 'gap': 3, 'max_green': 43, 'actuations': [0, 4, 7, 12, 14, 21, 24, 25, 41, 44, 47, 59], 'conflict_call': 10}, ['gap-out', 10]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3])], [({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15]), ({'min_green': 4, 'gap': 3, 'max_green': 31, 'actuations': [7, 8, 11, 14, 15, 21, 27, 32, 37, 46, 52, 57], 'conflict_call': None}, ['rest', 4]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 5, 'gap': 5, 'max_green': 22, 'actuations': [1, 3, 5, 9, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25, 27, 29, 31, 32, 34, 36, 37, 38, 40, 47, 49, 52, 55, 56, 57, 58, 59], 'conflict_call': 32}, ['gap-out', 45]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 5, 'gap': 4, 'max_green': 44, 'actuations': [1, 3, 4, 5, 6, 7, 10, 16, 17, 19, 20, 21, 25, 26, 28, 29, 32, 33, 34, 35, 38, 39, 41, 43, 44, 47, 49, 52, 56, 57, 58, 59], 'conflict_call': None}, ['rest', 14]), ({'min_green': 8, 'gap': 3, 'max_green': 29, 'actuations': [0, 2, 3, 6, 9, 11, 12, 14, 15, 17, 18, 19, 21, 22, 25, 27, 30, 31, 36, 38, 41, 42, 43, 45, 48, 52, 53, 55, 57, 59], 'conflict_call': 31}, ['gap-out', 34]), ({'min_green': 4, 'gap': 5, 'max_green': 45, 'actuations': [2, 3, 4, 5, 6, 7, 11, 12, 15, 17, 18, 20, 21, 22, 23, 25, 28, 29, 34, 35, 36, 37, 39, 41, 42, 49, 50, 51, 55, 56], 'conflict_call': 29}, ['gap-out', 47])], [({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12]), ({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15]), ({'min_green': 4, 'gap': 3, 'max_green': 33, 'actuations': [13, 36, 51, 10, 4, 20, 44, 6, 49, 32, 40, 7, 47, 14, 21, 31, 29, 8, 9, 56, 53, 50, 38, 5, 24, 27, 12, 17, 45, 52, 54], 'conflict_call': -6}, ['max-out', 33]), ({'min_green': 9, 'gap': 5, 'max_green': 34, 'actuations': [0, 2, 8, 9, 10, 11, 14, 16, 18, 23, 27, 29, 30, 31, 36, 38, 39, 40, 48, 50, 53, 55, 56], 'conflict_call': 33}, ['gap-out', 45]), ({'min_green': 10, 'gap': 5, 'max_green': 28, 'actuations': [13, 1, 18, 8, 59, 45, 3, 31, 4, 36, 12, 50, 6, 46, 7, 34, 40, 54, 19, 53, 48, 20, 52, 25, 57, 47, 5, 24, 16], 'conflict_call': 31}, ['gap-out', 31]), ({'min_green': 7, 'gap': 2, 'max_green': 31, 'actuations': [0, 2, 3, 7, 9, 19, 21, 23, 25, 28, 30, 38, 41, 43, 44, 48, 49, 51, 53, 56, 57], 'conflict_call': None}, ['rest', 11]), ({'min_green': 8, 'gap': 4, 'max_green': 44, 'actuations': [0, 2, 4, 6, 9, 12, 13, 15, 17, 18, 19, 23, 26, 29, 30, 32, 33, 35, 36, 38, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 55, 56], 'conflict_call': 15}, ['max-out', 59])], [({'min_green': 7, 'gap': 5, 'max_green': 38, 'actuations': [1, 3, 5, 6, 8, 9, 10, 11, 12, 13, 16, 18, 21, 23, 25, 26, 29, 31, 33, 34, 37, 38, 40, 41, 43, 44, 46, 48, 53, 54, 56, 57, 59], 'conflict_call': 12}, ['max-out', 50]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 7, 'gap': 3, 'max_green': 19, 'actuations': [0, 2, 5, 6, 7, 12, 15, 17, 21, 24, 25, 26, 27, 28, 29, 33, 34, 36, 38, 39, 40, 41, 44, 45, 47, 49, 50, 53, 54, 56], 'conflict_call': 0}, ['gap-out', 10]), ({'min_green': 6, 'gap': 2, 'max_green': 12, 'actuations': [1, 3, 5, 7, 9, 11, 13], 'conflict_call': 3}, ['gap-out', 15]), ({'min_green': 5, 'gap': 4, 'max_green': 41, 'actuations': [1, 2, 4, 6, 7, 8, 10, 13, 14, 17, 18, 19, 20, 21, 25, 26, 27, 28, 32, 35, 37, 38, 39, 40, 41, 43, 45, 47, 48, 50, 54, 55, 59], 'conflict_call': 31}, ['gap-out', 63]), ({'min_green': 10, 'gap': 4, 'max_green': 21, 'actuations': [5, 30, 36, 38, 46, 55], 'conflict_call': 34}, ['gap-out', 34]), ({'min_green': 4, 'gap': 5, 'max_green': 28, 'actuations': [2, 7, 57], 'conflict_call': None}, ['rest', 12]), ({'min_green': 6, 'gap': 2, 'max_green': 15, 'actuations': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], 'conflict_call': -3}, ['max-out', 15])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check('timing 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
timing oracle 0['gap-out', 15]['gap-out', 15]Passed
timing oracle 1['gap-out', 62]['gap-out', 62]Passed
timing oracle 2['max-out', 57]['max-out', 57]Passed
timing oracle 3['gap-out', 23]['gap-out', 23]Passed
timing oracle 4['max-out', 3]['max-out', 3]Passed
timing oracle 5['gap-out', 16]['gap-out', 16]Passed
timing oracle 6['gap-out', 20]['gap-out', 20]Passed
timing oracle 7['gap-out', 49]['gap-out', 49]Passed

SHA-256 / eece92289fd2b32c7b078480a6b72ceafd8de8a1191675ae710dc55c66d0fc2d

Verification & scope

A deterministic, bounded toy model with a stipulated contract; it makes no claim of conformance to any agency manual or 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:47:57.886220+00:00.

Case digest / 6dcd5f2c54d3575f4c394ae74423d127068a9ca9708f0860e9e7aa79cf59c178