FAILURE MAP
← Case archive

FA-66956 / Railway interlocking logic / Open access

Sectional route release: duplicate release · case 01

A section appears twice in the release list after being re-occupied.

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

ROOT CAUSE

Nothing prevents releasing a section that is already released.

VERIFIED REPAIR

Skip sections that are already in the release list.

Unsuccessful approach: Only suppressing an immediate repeat still duplicates a section released earlier.

Case contract

Sections of a locked route are released in route order as the train passes. A section is released when it clears, it was seen occupied earlier, its predecessor is already released (or it is the first), and the next route section is currently occupied (or it is the last). A clear of a never-occupied route section latches a fault that stops all further release. Events for sections outside the route are ignored. Output released sections in release order and the fault flag.

Why this case matters

Interlocking logic decides whether trains may be given authority; a wrong decision at this point either grants unsafe movements or strands traffic.

1 / The failure

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

N = 1
observations = []
def solve(x):
    route = x['route']
    seen = set()
    released = []
    fault = False
    occ = set()
    for sec, ev in x['events']:
        if sec not in route:
            continue
        if ev == 'occ':
            occ.add(sec)
            seen.add(sec)
        else:
            if sec not in seen:
                fault = True
            occ.discard(sec)
            i = route.index(sec)
            nxt_ok = i == len(route) - 1 or route[i + 1] in occ
            prev_ok = i == 0 or route[i - 1] in released
            if not fault and nxt_ok and prev_ok :
                released.append(sec)
    return {'released': released, 'fault': fault}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 14', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T3', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: next section flickered earlier', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('sampled regression 1', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 4', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 7', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'clr'], ['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': [], 'fault': True})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 50', {'route': ['T1', 'T2', 'T3', 'T4', 'T5'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T5', 'occ'], ['T2', 'clr'], ['T4', 'clr'], ['T5', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4', 'T5'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: middle section clears before first', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('control 12', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('control 15', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T4', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('sampled regression 18', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T1', 'occ'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 71', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['Z9', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'occ'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('sampled regression 2', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2'], 'fault': False}), ('boundary: phantom clear on first section', {'route': ['T1', 'T2'], 'events': [['T1', 'clr'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr']]}, {'released': [], 'fault': True}), ('boundary: single section route', {'route': ['T1'], 'events': [['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('control 23', {'route': ['T1', 'T2', 'T3'], 'events': [['T3', 'clr'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': [], 'fault': True}), ('control 26', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T1', 'clr'], ['T4', 'clr'], ['T4', 'occ']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('control 29', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 45', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['Z9', 'occ'], ['T3', 'clr'], ['T4', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: single section route', {'route': ['T1'], 'events': [['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('control 34', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'occ'], ['Z9', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 37', {'route': ['T1', 'T2', 'T3', 'T4', 'T5'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T5', 'occ'], ['T4', 'clr'], ['T5', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4', 'T5'], 'fault': False}), ('control 40', {'route': ['T1', 'T2'], 'events': [['T2', 'occ'], ['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T2', 'clr']]}, {'released': [], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 1', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: next section flickered earlier', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('sampled regression 45', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['Z9', 'occ'], ['T3', 'clr'], ['T4', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('control 48', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['Z9', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': [], 'fault': True}), ('sampled regression 54', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False})]]
for label, args, expected in fixtures[N-1]:
    check(label, 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
regression: re-occupation after release{'fault': False, 'released': ['T1', 'T1']}{'fault': False, 'released': ['T1']}Failed
sampled regression 44{'fault': False, 'released': ['T1', 'T2', 'T3', 'T1']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Failed
sampled regression 14{'fault': False, 'released': ['T1', 'T1', 'T2', 'T3']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Failed
sampled regression 51{'fault': False, 'released': ['T1', 'T2', 'T3', 'T1']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Failed
boundary: next section flickered earlier{'fault': False, 'released': []}{'fault': False, 'released': []}Passed
sampled regression 1{'fault': False, 'released': ['T1', 'T2', 'T2']}{'fault': False, 'released': ['T1', 'T2']}Failed
control 4{'fault': False, 'released': ['T1', 'T2']}{'fault': False, 'released': ['T1', 'T2']}Passed
control 7{'fault': True, 'released': []}{'fault': True, 'released': []}Passed

SHA-256 / 0f96c12b16d41f45798f468f547fc122a9746dad8f06c5e3d48298dee8b34770

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    route = x['route']
    seen = set()
    released = []
    fault = False
    occ = set()
    for sec, ev in x['events']:
        if sec not in route:
            continue
        if ev == 'occ':
            occ.add(sec)
            seen.add(sec)
        else:
            if sec not in seen:
                fault = True
            occ.discard(sec)
            i = route.index(sec)
            nxt_ok = i == len(route) - 1 or route[i + 1] in occ
            prev_ok = i == 0 or route[i - 1] in released
            if not fault and nxt_ok and prev_ok and released[-1:] != [sec]:
                released.append(sec)
    return {'released': released, 'fault': fault}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 14', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T3', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: next section flickered earlier', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('sampled regression 1', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 4', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 7', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'clr'], ['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': [], 'fault': True})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 50', {'route': ['T1', 'T2', 'T3', 'T4', 'T5'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T5', 'occ'], ['T2', 'clr'], ['T4', 'clr'], ['T5', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4', 'T5'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: middle section clears before first', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('control 12', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('control 15', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T4', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('sampled regression 18', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T1', 'occ'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 71', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['Z9', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'occ'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('sampled regression 2', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2'], 'fault': False}), ('boundary: phantom clear on first section', {'route': ['T1', 'T2'], 'events': [['T1', 'clr'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr']]}, {'released': [], 'fault': True}), ('boundary: single section route', {'route': ['T1'], 'events': [['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('control 23', {'route': ['T1', 'T2', 'T3'], 'events': [['T3', 'clr'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': [], 'fault': True}), ('control 26', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T1', 'clr'], ['T4', 'clr'], ['T4', 'occ']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('control 29', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 45', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['Z9', 'occ'], ['T3', 'clr'], ['T4', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: single section route', {'route': ['T1'], 'events': [['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('control 34', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'occ'], ['Z9', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 37', {'route': ['T1', 'T2', 'T3', 'T4', 'T5'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T5', 'occ'], ['T4', 'clr'], ['T5', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4', 'T5'], 'fault': False}), ('control 40', {'route': ['T1', 'T2'], 'events': [['T2', 'occ'], ['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T2', 'clr']]}, {'released': [], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 1', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: next section flickered earlier', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('sampled regression 45', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['Z9', 'occ'], ['T3', 'clr'], ['T4', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('control 48', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['Z9', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': [], 'fault': True}), ('sampled regression 54', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False})]]
for label, args, expected in fixtures[N-1]:
    check(label, 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
regression: re-occupation after release{'fault': False, 'released': ['T1']}{'fault': False, 'released': ['T1']}Passed
sampled regression 44{'fault': False, 'released': ['T1', 'T2', 'T3', 'T1']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Failed
sampled regression 14{'fault': False, 'released': ['T1', 'T2', 'T3']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Passed
sampled regression 51{'fault': False, 'released': ['T1', 'T2', 'T3', 'T1']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Failed
boundary: next section flickered earlier{'fault': False, 'released': []}{'fault': False, 'released': []}Passed
sampled regression 1{'fault': False, 'released': ['T1', 'T2']}{'fault': False, 'released': ['T1', 'T2']}Passed
control 4{'fault': False, 'released': ['T1', 'T2']}{'fault': False, 'released': ['T1', 'T2']}Passed
control 7{'fault': True, 'released': []}{'fault': True, 'released': []}Passed

SHA-256 / afa1db516b4df2e6d2824db82db75f3d621e926b6658ef387747844ea8355da1

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    route = x['route']
    seen = set()
    released = []
    fault = False
    occ = set()
    for sec, ev in x['events']:
        if sec not in route:
            continue
        if ev == 'occ':
            occ.add(sec)
            seen.add(sec)
        else:
            if sec not in seen:
                fault = True
            occ.discard(sec)
            i = route.index(sec)
            nxt_ok = i == len(route) - 1 or route[i + 1] in occ
            prev_ok = i == 0 or route[i - 1] in released
            if not fault and nxt_ok and prev_ok and sec not in released:
                released.append(sec)
    return {'released': released, 'fault': fault}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 14', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T3', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: next section flickered earlier', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('sampled regression 1', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 4', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 7', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'clr'], ['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': [], 'fault': True})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 50', {'route': ['T1', 'T2', 'T3', 'T4', 'T5'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T5', 'occ'], ['T2', 'clr'], ['T4', 'clr'], ['T5', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4', 'T5'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: middle section clears before first', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('control 12', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('control 15', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T4', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('sampled regression 18', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T1', 'occ'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 71', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['Z9', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'occ'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('sampled regression 2', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2'], 'fault': False}), ('boundary: phantom clear on first section', {'route': ['T1', 'T2'], 'events': [['T1', 'clr'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr']]}, {'released': [], 'fault': True}), ('boundary: single section route', {'route': ['T1'], 'events': [['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('control 23', {'route': ['T1', 'T2', 'T3'], 'events': [['T3', 'clr'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': [], 'fault': True}), ('control 26', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T1', 'clr'], ['T4', 'clr'], ['T4', 'occ']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('control 29', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 45', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['Z9', 'occ'], ['T3', 'clr'], ['T4', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: single section route', {'route': ['T1'], 'events': [['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('control 34', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'occ'], ['Z9', 'clr'], ['T1', 'clr'], ['T2', 'clr'], ['Z9', 'occ']]}, {'released': ['T1', 'T2'], 'fault': False}), ('control 37', {'route': ['T1', 'T2', 'T3', 'T4', 'T5'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['T3', 'clr'], ['T5', 'occ'], ['T4', 'clr'], ['T5', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4', 'T5'], 'fault': False}), ('control 40', {'route': ['T1', 'T2'], 'events': [['T2', 'occ'], ['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T2', 'clr']]}, {'released': [], 'fault': False})], [('regression: re-occupation after release', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1'], 'fault': False}), ('sampled regression 51', {'route': ['T1', 'T2', 'T3'], 'events': [['Z9', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('sampled regression 1', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T2', 'occ'], ['Z9', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T2', 'clr']]}, {'released': ['T1', 'T2'], 'fault': False}), ('sampled regression 44', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['Z9', 'clr'], ['T3', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False}), ('boundary: next section flickered earlier', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T2', 'occ'], ['T2', 'clr'], ['T1', 'clr']]}, {'released': [], 'fault': False}), ('sampled regression 45', {'route': ['T1', 'T2', 'T3', 'T4'], 'events': [['T1', 'occ'], ['T3', 'occ'], ['T2', 'occ'], ['T1', 'clr'], ['T1', 'clr'], ['T3', 'occ'], ['T2', 'clr'], ['T4', 'occ'], ['Z9', 'occ'], ['T3', 'clr'], ['T4', 'clr']]}, {'released': ['T1', 'T2', 'T3', 'T4'], 'fault': False}), ('control 48', {'route': ['T1', 'T2'], 'events': [['T1', 'occ'], ['Z9', 'occ'], ['T2', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T1', 'occ'], ['T1', 'clr']]}, {'released': [], 'fault': True}), ('sampled regression 54', {'route': ['T1', 'T2', 'T3'], 'events': [['T1', 'occ'], ['T1', 'occ'], ['T1', 'clr'], ['T2', 'occ'], ['T1', 'clr'], ['T3', 'occ'], ['T1', 'clr'], ['T2', 'clr'], ['T3', 'clr']]}, {'released': ['T1', 'T2', 'T3'], 'fault': False})]]
for label, args, expected in fixtures[N-1]:
    check(label, 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
regression: re-occupation after release{'fault': False, 'released': ['T1']}{'fault': False, 'released': ['T1']}Passed
sampled regression 44{'fault': False, 'released': ['T1', 'T2', 'T3']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Passed
sampled regression 14{'fault': False, 'released': ['T1', 'T2', 'T3']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Passed
sampled regression 51{'fault': False, 'released': ['T1', 'T2', 'T3']}{'fault': False, 'released': ['T1', 'T2', 'T3']}Passed
boundary: next section flickered earlier{'fault': False, 'released': []}{'fault': False, 'released': []}Passed
sampled regression 1{'fault': False, 'released': ['T1', 'T2']}{'fault': False, 'released': ['T1', 'T2']}Passed
control 4{'fault': False, 'released': ['T1', 'T2']}{'fault': False, 'released': ['T1', 'T2']}Passed
control 7{'fault': True, 'released': []}{'fault': True, 'released': []}Passed

SHA-256 / 7996be22a76c98b52ea847aceb8e7be5789e272588b7d7bdc67085a65e5ed7f5

Verification & scope

Stipulated toy interlocking contract for a bounded teaching model; it makes no claim of conformance to any railway signalling standard and omits real safety cases. 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:48.521043+00:00.

Case digest / 6f9a3b0b6c3c0dd22aa1c41ce4da3d1d72dc06b40ee6c3d15cfd22afbc72091b