FAILURE MAP
← Case archive

FA-67996 / Traffic signal timing plans / Open access

Actuated phase gap-out and max-out: a phase without a conflicting call reports a gap-out · case 01

Actuated phase gap-out and max-out returns a wrong result when a phase without a conflicting call reports a gap-out.

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

ROOT CAUSE

With no conflicting demand the phase must rest in green; reporting gap-out would terminate it needlessly.

VERIFIED REPAIR

Restore the no-call verdict rule so that the step reads `return ['rest', gap_end]`.

Unsuccessful approach: Reporting the rest state at min green loses the time at which the passage timer actually expired.

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 ['gap-out', 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': 9, 'gap': 4, 'max_green': 41, 'actuations': [29, 38, 20, 27, 14, 32, 45, 46, 25, 35, 30, 43, 12, 7, 4, 34, 48, 11], 'conflict_call': None}, ['rest', 18]), ({'min_green': 6, 'gap': 5, 'max_green': 34, 'actuations': [1, 2, 3, 4, 11, 13, 14, 15, 18, 20, 22, 23, 24, 25, 26, 28, 31, 35, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 52, 53, 54, 58, 59], 'conflict_call': 11}, ['gap-out', 11]), ({'min_green': 5, 'gap': 3, 'max_green': 15, 'actuations': [2, 21, 25, 43, 48, 59], 'conflict_call': 10}, ['gap-out', 10]), ({'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': 9, 'gap': 2, 'max_green': 19, 'actuations': [3, 6, 9, 10, 16, 22, 25, 26, 31, 34, 36, 41, 42, 43, 44, 49, 50, 52, 57, 59], 'conflict_call': 7}, ['gap-out', 12]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 6, 'gap': 4, 'max_green': 39, 'actuations': [0, 4, 9, 12, 14, 16, 22, 23, 26, 29, 34, 35, 41, 45, 47, 54, 56, 58], 'conflict_call': None}, ['rest', 8]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12])], [({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 8, 'gap': 4, 'max_green': 31, 'actuations': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 16, 17, 18, 19, 22, 25, 27, 31, 33, 35, 36, 44, 46, 48, 49, 53, 56, 57, 59], 'conflict_call': None}, ['rest', 40]), ({'min_green': 7, 'gap': 5, 'max_green': 26, 'actuations': [1, 2, 17, 18, 25, 34, 44, 45, 47, 55], 'conflict_call': None}, ['rest', 7]), ({'min_green': 4, 'gap': 4, 'max_green': 19, 'actuations': [0, 2, 3, 11, 12, 14, 16, 21, 23, 27, 29, 30, 31, 32, 43, 45, 46, 47, 48, 49, 59], 'conflict_call': 33}, ['gap-out', 33]), ({'min_green': 8, 'gap': 4, 'max_green': 43, 'actuations': [38, 33, 28, 12, 27, 43, 11, 17, 59, 1, 21], 'conflict_call': None}, ['rest', 8]), ({'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': 10, 'gap': 5, 'max_green': 24, 'actuations': [0, 2, 3, 6, 8, 10, 11, 12, 13, 14, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 47, 49, 50, 51, 52, 53], 'conflict_call': None}, ['rest', 19]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3])], [({'min_green': 6, 'gap': 5, 'max_green': 35, 'actuations': [7, 49, 54, 39, 46, 35, 28, 18, 47, 33], 'conflict_call': -2}, ['gap-out', 6]), ({'min_green': 5, 'gap': 3, 'max_green': 18, 'actuations': [15, 33, 35, 48, 57], 'conflict_call': None}, ['rest', 5]), ({'min_green': 12, 'gap': 3, 'max_green': 5, 'actuations': [1], 'conflict_call': 2}, ['max-out', 7]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 5, 'gap': 3, 'max_green': 41, 'actuations': [0, 2, 4, 10, 13, 14, 35, 37, 39, 47, 48, 53, 54, 55], 'conflict_call': 35}, ['gap-out', 35]), ({'min_green': 5, 'gap': 2, 'max_green': 42, 'actuations': [22, 2, 3, 11, 44, 15, 38, 20, 5, 12, 36, 24, 4, 23, 34, 50, 56, 57, 54, 30, 1, 0, 39, 41, 29, 40, 45, 9, 58, 53, 17, 21, 55, 27, 32, 35, 43, 28], 'conflict_call': None}, ['rest', 7]), ({'min_green': 10, 'gap': 2, 'max_green': 25, 'actuations': [25, 26, 9, 22, 29, 6, 2, 50], 'conflict_call': None}, ['rest', 11]), ({'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': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 6, 'gap': 3, 'max_green': 34, 'actuations': [55, 46, 15, 21, 43, 38, 47, 58, 45, 29, 41, 19, 0, 31, 57, 13, 40, 52, 39, 49, 14, 6], 'conflict_call': 18}, ['gap-out', 18]), ({'min_green': 6, 'gap': 2, 'max_green': 42, 'actuations': [2, 14, 15, 17, 19, 27, 28, 31, 34, 46], 'conflict_call': None}, ['rest', 6]), ({'min_green': 6, 'gap': 2, 'max_green': 12, 'actuations': [1, 3, 5, 7, 9, 11, 13], 'conflict_call': 3}, ['gap-out', 15]), ({'min_green': 6, 'gap': 3, 'max_green': 27, 'actuations': [1, 5, 6, 7, 9, 11, 13, 16, 17, 23, 25, 27, 29, 32, 37, 39, 40, 42, 44, 45, 46, 48, 53, 55, 56, 58, 59], 'conflict_call': 31}, ['gap-out', 31]), ({'min_green': 5, 'gap': 3, 'max_green': 10, 'actuations': [0, 3, 6, 9, 12], 'conflict_call': 5}, ['gap-out', 15]), ({'min_green': 5, 'gap': 5, 'max_green': 18, 'actuations': [2, 3, 15, 24, 26, 27, 32, 34, 35, 37, 46, 51, 54, 59], 'conflict_call': None}, ['rest', 8]), ({'min_green': 6, 'gap': 3, 'max_green': 28, 'actuations': [1, 2, 6, 10, 24, 29, 31, 35, 36, 41, 51, 53], 'conflict_call': None}, ['rest', 9])], [({'min_green': 7, 'gap': 3, 'max_green': 23, 'actuations': [1, 3, 4, 5, 6, 8, 9, 13, 17, 18, 19, 21, 26, 28, 30, 31, 38, 39, 42, 44, 45, 48, 53, 55, 56, 57], 'conflict_call': 9}, ['gap-out', 12]), ({'min_green': 4, 'gap': 5, 'max_green': 43, 'actuations': [4, 7, 12, 17, 18, 22, 24, 25, 29, 30, 32, 39, 45, 48, 55, 56, 59], 'conflict_call': None}, ['rest', 37]), ({'min_green': 6, 'gap': 4, 'max_green': 16, 'actuations': [36, 59, 43, 57, 30, 45, 23, 28, 37, 17, 56, 12, 13, 48, 29, 38, 20, 5, 42, 11, 41], 'conflict_call': None}, ['rest', 9]), ({'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': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 9, 'gap': 2, 'max_green': 35, 'actuations': [0, 10, 11, 12, 14, 15, 16, 18, 26, 28, 31, 32, 35, 37, 40, 43, 45, 46, 47, 51, 54], 'conflict_call': None}, ['rest', 9]), ({'min_green': 4, 'gap': 2, 'max_green': 26, 'actuations': [46, 4, 6, 1, 50, 19, 33, 51, 15, 34, 49, 58, 32, 29, 14, 24, 40], 'conflict_call': 35}, ['gap-out', 35]), ({'min_green': 5, 'gap': 3, 'max_green': 20, 'actuations': [1, 4, 7, 10, 13], 'conflict_call': 2}, ['gap-out', 16])]]
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', 18]['rest', 18]Failed
timing oracle 1['gap-out', 11]['gap-out', 11]Passed
timing oracle 2['gap-out', 10]['gap-out', 10]Passed
timing oracle 3['max-out', 15]['max-out', 15]Passed
timing oracle 4['gap-out', 12]['gap-out', 12]Passed
timing oracle 5['max-out', 3]['max-out', 3]Passed
timing oracle 6['gap-out', 8]['rest', 8]Failed
timing oracle 7['gap-out', 12]['rest', 12]Failed

SHA-256 / a2ff733782697fefee488b1a8b193eece1f1e6b69e6946d5dd0ab0c66d850992

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', m]
    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': 9, 'gap': 4, 'max_green': 41, 'actuations': [29, 38, 20, 27, 14, 32, 45, 46, 25, 35, 30, 43, 12, 7, 4, 34, 48, 11], 'conflict_call': None}, ['rest', 18]), ({'min_green': 6, 'gap': 5, 'max_green': 34, 'actuations': [1, 2, 3, 4, 11, 13, 14, 15, 18, 20, 22, 23, 24, 25, 26, 28, 31, 35, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 52, 53, 54, 58, 59], 'conflict_call': 11}, ['gap-out', 11]), ({'min_green': 5, 'gap': 3, 'max_green': 15, 'actuations': [2, 21, 25, 43, 48, 59], 'conflict_call': 10}, ['gap-out', 10]), ({'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': 9, 'gap': 2, 'max_green': 19, 'actuations': [3, 6, 9, 10, 16, 22, 25, 26, 31, 34, 36, 41, 42, 43, 44, 49, 50, 52, 57, 59], 'conflict_call': 7}, ['gap-out', 12]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 6, 'gap': 4, 'max_green': 39, 'actuations': [0, 4, 9, 12, 14, 16, 22, 23, 26, 29, 34, 35, 41, 45, 47, 54, 56, 58], 'conflict_call': None}, ['rest', 8]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12])], [({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 8, 'gap': 4, 'max_green': 31, 'actuations': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 16, 17, 18, 19, 22, 25, 27, 31, 33, 35, 36, 44, 46, 48, 49, 53, 56, 57, 59], 'conflict_call': None}, ['rest', 40]), ({'min_green': 7, 'gap': 5, 'max_green': 26, 'actuations': [1, 2, 17, 18, 25, 34, 44, 45, 47, 55], 'conflict_call': None}, ['rest', 7]), ({'min_green': 4, 'gap': 4, 'max_green': 19, 'actuations': [0, 2, 3, 11, 12, 14, 16, 21, 23, 27, 29, 30, 31, 32, 43, 45, 46, 47, 48, 49, 59], 'conflict_call': 33}, ['gap-out', 33]), ({'min_green': 8, 'gap': 4, 'max_green': 43, 'actuations': [38, 33, 28, 12, 27, 43, 11, 17, 59, 1, 21], 'conflict_call': None}, ['rest', 8]), ({'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': 10, 'gap': 5, 'max_green': 24, 'actuations': [0, 2, 3, 6, 8, 10, 11, 12, 13, 14, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 47, 49, 50, 51, 52, 53], 'conflict_call': None}, ['rest', 19]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3])], [({'min_green': 6, 'gap': 5, 'max_green': 35, 'actuations': [7, 49, 54, 39, 46, 35, 28, 18, 47, 33], 'conflict_call': -2}, ['gap-out', 6]), ({'min_green': 5, 'gap': 3, 'max_green': 18, 'actuations': [15, 33, 35, 48, 57], 'conflict_call': None}, ['rest', 5]), ({'min_green': 12, 'gap': 3, 'max_green': 5, 'actuations': [1], 'conflict_call': 2}, ['max-out', 7]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 5, 'gap': 3, 'max_green': 41, 'actuations': [0, 2, 4, 10, 13, 14, 35, 37, 39, 47, 48, 53, 54, 55], 'conflict_call': 35}, ['gap-out', 35]), ({'min_green': 5, 'gap': 2, 'max_green': 42, 'actuations': [22, 2, 3, 11, 44, 15, 38, 20, 5, 12, 36, 24, 4, 23, 34, 50, 56, 57, 54, 30, 1, 0, 39, 41, 29, 40, 45, 9, 58, 53, 17, 21, 55, 27, 32, 35, 43, 28], 'conflict_call': None}, ['rest', 7]), ({'min_green': 10, 'gap': 2, 'max_green': 25, 'actuations': [25, 26, 9, 22, 29, 6, 2, 50], 'conflict_call': None}, ['rest', 11]), ({'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': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 6, 'gap': 3, 'max_green': 34, 'actuations': [55, 46, 15, 21, 43, 38, 47, 58, 45, 29, 41, 19, 0, 31, 57, 13, 40, 52, 39, 49, 14, 6], 'conflict_call': 18}, ['gap-out', 18]), ({'min_green': 6, 'gap': 2, 'max_green': 42, 'actuations': [2, 14, 15, 17, 19, 27, 28, 31, 34, 46], 'conflict_call': None}, ['rest', 6]), ({'min_green': 6, 'gap': 2, 'max_green': 12, 'actuations': [1, 3, 5, 7, 9, 11, 13], 'conflict_call': 3}, ['gap-out', 15]), ({'min_green': 6, 'gap': 3, 'max_green': 27, 'actuations': [1, 5, 6, 7, 9, 11, 13, 16, 17, 23, 25, 27, 29, 32, 37, 39, 40, 42, 44, 45, 46, 48, 53, 55, 56, 58, 59], 'conflict_call': 31}, ['gap-out', 31]), ({'min_green': 5, 'gap': 3, 'max_green': 10, 'actuations': [0, 3, 6, 9, 12], 'conflict_call': 5}, ['gap-out', 15]), ({'min_green': 5, 'gap': 5, 'max_green': 18, 'actuations': [2, 3, 15, 24, 26, 27, 32, 34, 35, 37, 46, 51, 54, 59], 'conflict_call': None}, ['rest', 8]), ({'min_green': 6, 'gap': 3, 'max_green': 28, 'actuations': [1, 2, 6, 10, 24, 29, 31, 35, 36, 41, 51, 53], 'conflict_call': None}, ['rest', 9])], [({'min_green': 7, 'gap': 3, 'max_green': 23, 'actuations': [1, 3, 4, 5, 6, 8, 9, 13, 17, 18, 19, 21, 26, 28, 30, 31, 38, 39, 42, 44, 45, 48, 53, 55, 56, 57], 'conflict_call': 9}, ['gap-out', 12]), ({'min_green': 4, 'gap': 5, 'max_green': 43, 'actuations': [4, 7, 12, 17, 18, 22, 24, 25, 29, 30, 32, 39, 45, 48, 55, 56, 59], 'conflict_call': None}, ['rest', 37]), ({'min_green': 6, 'gap': 4, 'max_green': 16, 'actuations': [36, 59, 43, 57, 30, 45, 23, 28, 37, 17, 56, 12, 13, 48, 29, 38, 20, 5, 42, 11, 41], 'conflict_call': None}, ['rest', 9]), ({'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': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 9, 'gap': 2, 'max_green': 35, 'actuations': [0, 10, 11, 12, 14, 15, 16, 18, 26, 28, 31, 32, 35, 37, 40, 43, 45, 46, 47, 51, 54], 'conflict_call': None}, ['rest', 9]), ({'min_green': 4, 'gap': 2, 'max_green': 26, 'actuations': [46, 4, 6, 1, 50, 19, 33, 51, 15, 34, 49, 58, 32, 29, 14, 24, 40], 'conflict_call': 35}, ['gap-out', 35]), ({'min_green': 5, 'gap': 3, 'max_green': 20, 'actuations': [1, 4, 7, 10, 13], 'conflict_call': 2}, ['gap-out', 16])]]
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['rest', 9]['rest', 18]Failed
timing oracle 1['gap-out', 11]['gap-out', 11]Passed
timing oracle 2['gap-out', 10]['gap-out', 10]Passed
timing oracle 3['max-out', 15]['max-out', 15]Passed
timing oracle 4['gap-out', 12]['gap-out', 12]Passed
timing oracle 5['max-out', 3]['max-out', 3]Passed
timing oracle 6['rest', 6]['rest', 8]Failed
timing oracle 7['rest', 5]['rest', 12]Failed

SHA-256 / 5f4a1f76cbcf858518c2533cdc3d02e0996d17220d2a3a403a4984c1f18c32a2

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': 9, 'gap': 4, 'max_green': 41, 'actuations': [29, 38, 20, 27, 14, 32, 45, 46, 25, 35, 30, 43, 12, 7, 4, 34, 48, 11], 'conflict_call': None}, ['rest', 18]), ({'min_green': 6, 'gap': 5, 'max_green': 34, 'actuations': [1, 2, 3, 4, 11, 13, 14, 15, 18, 20, 22, 23, 24, 25, 26, 28, 31, 35, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 52, 53, 54, 58, 59], 'conflict_call': 11}, ['gap-out', 11]), ({'min_green': 5, 'gap': 3, 'max_green': 15, 'actuations': [2, 21, 25, 43, 48, 59], 'conflict_call': 10}, ['gap-out', 10]), ({'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': 9, 'gap': 2, 'max_green': 19, 'actuations': [3, 6, 9, 10, 16, 22, 25, 26, 31, 34, 36, 41, 42, 43, 44, 49, 50, 52, 57, 59], 'conflict_call': 7}, ['gap-out', 12]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3]), ({'min_green': 6, 'gap': 4, 'max_green': 39, 'actuations': [0, 4, 9, 12, 14, 16, 22, 23, 26, 29, 34, 35, 41, 45, 47, 54, 56, 58], 'conflict_call': None}, ['rest', 8]), ({'min_green': 5, 'gap': 3, 'max_green': 25, 'actuations': [9, 3, 6], 'conflict_call': None}, ['rest', 12])], [({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 8, 'gap': 4, 'max_green': 31, 'actuations': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 16, 17, 18, 19, 22, 25, 27, 31, 33, 35, 36, 44, 46, 48, 49, 53, 56, 57, 59], 'conflict_call': None}, ['rest', 40]), ({'min_green': 7, 'gap': 5, 'max_green': 26, 'actuations': [1, 2, 17, 18, 25, 34, 44, 45, 47, 55], 'conflict_call': None}, ['rest', 7]), ({'min_green': 4, 'gap': 4, 'max_green': 19, 'actuations': [0, 2, 3, 11, 12, 14, 16, 21, 23, 27, 29, 30, 31, 32, 43, 45, 46, 47, 48, 49, 59], 'conflict_call': 33}, ['gap-out', 33]), ({'min_green': 8, 'gap': 4, 'max_green': 43, 'actuations': [38, 33, 28, 12, 27, 43, 11, 17, 59, 1, 21], 'conflict_call': None}, ['rest', 8]), ({'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': 10, 'gap': 5, 'max_green': 24, 'actuations': [0, 2, 3, 6, 8, 10, 11, 12, 13, 14, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 47, 49, 50, 51, 52, 53], 'conflict_call': None}, ['rest', 19]), ({'min_green': 10, 'gap': 2, 'max_green': 3, 'actuations': [], 'conflict_call': 0}, ['max-out', 3])], [({'min_green': 6, 'gap': 5, 'max_green': 35, 'actuations': [7, 49, 54, 39, 46, 35, 28, 18, 47, 33], 'conflict_call': -2}, ['gap-out', 6]), ({'min_green': 5, 'gap': 3, 'max_green': 18, 'actuations': [15, 33, 35, 48, 57], 'conflict_call': None}, ['rest', 5]), ({'min_green': 12, 'gap': 3, 'max_green': 5, 'actuations': [1], 'conflict_call': 2}, ['max-out', 7]), ({'min_green': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 5, 'gap': 3, 'max_green': 41, 'actuations': [0, 2, 4, 10, 13, 14, 35, 37, 39, 47, 48, 53, 54, 55], 'conflict_call': 35}, ['gap-out', 35]), ({'min_green': 5, 'gap': 2, 'max_green': 42, 'actuations': [22, 2, 3, 11, 44, 15, 38, 20, 5, 12, 36, 24, 4, 23, 34, 50, 56, 57, 54, 30, 1, 0, 39, 41, 29, 40, 45, 9, 58, 53, 17, 21, 55, 27, 32, 35, 43, 28], 'conflict_call': None}, ['rest', 7]), ({'min_green': 10, 'gap': 2, 'max_green': 25, 'actuations': [25, 26, 9, 22, 29, 6, 2, 50], 'conflict_call': None}, ['rest', 11]), ({'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': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 6, 'gap': 3, 'max_green': 34, 'actuations': [55, 46, 15, 21, 43, 38, 47, 58, 45, 29, 41, 19, 0, 31, 57, 13, 40, 52, 39, 49, 14, 6], 'conflict_call': 18}, ['gap-out', 18]), ({'min_green': 6, 'gap': 2, 'max_green': 42, 'actuations': [2, 14, 15, 17, 19, 27, 28, 31, 34, 46], 'conflict_call': None}, ['rest', 6]), ({'min_green': 6, 'gap': 2, 'max_green': 12, 'actuations': [1, 3, 5, 7, 9, 11, 13], 'conflict_call': 3}, ['gap-out', 15]), ({'min_green': 6, 'gap': 3, 'max_green': 27, 'actuations': [1, 5, 6, 7, 9, 11, 13, 16, 17, 23, 25, 27, 29, 32, 37, 39, 40, 42, 44, 45, 46, 48, 53, 55, 56, 58, 59], 'conflict_call': 31}, ['gap-out', 31]), ({'min_green': 5, 'gap': 3, 'max_green': 10, 'actuations': [0, 3, 6, 9, 12], 'conflict_call': 5}, ['gap-out', 15]), ({'min_green': 5, 'gap': 5, 'max_green': 18, 'actuations': [2, 3, 15, 24, 26, 27, 32, 34, 35, 37, 46, 51, 54, 59], 'conflict_call': None}, ['rest', 8]), ({'min_green': 6, 'gap': 3, 'max_green': 28, 'actuations': [1, 2, 6, 10, 24, 29, 31, 35, 36, 41, 51, 53], 'conflict_call': None}, ['rest', 9])], [({'min_green': 7, 'gap': 3, 'max_green': 23, 'actuations': [1, 3, 4, 5, 6, 8, 9, 13, 17, 18, 19, 21, 26, 28, 30, 31, 38, 39, 42, 44, 45, 48, 53, 55, 56, 57], 'conflict_call': 9}, ['gap-out', 12]), ({'min_green': 4, 'gap': 5, 'max_green': 43, 'actuations': [4, 7, 12, 17, 18, 22, 24, 25, 29, 30, 32, 39, 45, 48, 55, 56, 59], 'conflict_call': None}, ['rest', 37]), ({'min_green': 6, 'gap': 4, 'max_green': 16, 'actuations': [36, 59, 43, 57, 30, 45, 23, 28, 37, 17, 56, 12, 13, 48, 29, 38, 20, 5, 42, 11, 41], 'conflict_call': None}, ['rest', 9]), ({'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': 8, 'gap': 3, 'max_green': 30, 'actuations': [2, 6], 'conflict_call': 20}, ['gap-out', 20]), ({'min_green': 9, 'gap': 2, 'max_green': 35, 'actuations': [0, 10, 11, 12, 14, 15, 16, 18, 26, 28, 31, 32, 35, 37, 40, 43, 45, 46, 47, 51, 54], 'conflict_call': None}, ['rest', 9]), ({'min_green': 4, 'gap': 2, 'max_green': 26, 'actuations': [46, 4, 6, 1, 50, 19, 33, 51, 15, 34, 49, 58, 32, 29, 14, 24, 40], 'conflict_call': 35}, ['gap-out', 35]), ({'min_green': 5, 'gap': 3, 'max_green': 20, 'actuations': [1, 4, 7, 10, 13], 'conflict_call': 2}, ['gap-out', 16])]]
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['rest', 18]['rest', 18]Passed
timing oracle 1['gap-out', 11]['gap-out', 11]Passed
timing oracle 2['gap-out', 10]['gap-out', 10]Passed
timing oracle 3['max-out', 15]['max-out', 15]Passed
timing oracle 4['gap-out', 12]['gap-out', 12]Passed
timing oracle 5['max-out', 3]['max-out', 3]Passed
timing oracle 6['rest', 8]['rest', 8]Passed
timing oracle 7['rest', 12]['rest', 12]Passed

SHA-256 / c9a7da90a69734ef4aa836320cbdafc55604f9c40351bbd26c18779358296b15

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

Case digest / 8abdb0727b56a911210dc7f19d5137f3dfb1d54f557a38c4f59caeb53208970e