FA-67046 / Railway interlocking logic / Open access
Absolute block bell-code working: departure authority · case 01
A second train entering an occupied block raises no alarm.
ROOT CAUSE
Only a departure from the normal state is treated as unauthorised.
VERIFIED REPAIR
Alarm on any departure that was not preceded by line clear.
Unsuccessful approach: Alarming only when a train is already on line misses a departure with no offer at all.
Case contract
A block section between two boxes is normal, line_clear or train_on_line. An offer is accepted (line_clear) only from normal with the clearing point clear, otherwise alarm refused. A departure without line clear raises unauthorised-departure; any departure puts the train on line. arrive_complete returns train_on_line to normal; arrive_no_tail raises tail-missing and keeps the block occupied. cancel only withdraws line_clear. cp_blocked/cp_clear set the clearing point.
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):
state = 'normal'
cp = True
alarms = []
for ev in x['events']:
if ev == 'cp_blocked':
cp = False
elif ev == 'cp_clear':
cp = True
elif ev == 'offer':
if state == 'normal' and cp:
state = 'line_clear'
else:
alarms.append('refused')
elif ev == 'depart':
if state == 'normal':
alarms.append('unauthorised-departure')
state = 'train_on_line'
elif ev == 'arrive_complete':
if state == 'train_on_line':
state = 'normal'
elif ev == 'arrive_no_tail':
alarms.append('tail-missing')
elif ev == 'cancel':
if state == 'line_clear':
state = 'normal'
return {'state': state, 'alarms': alarms}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 5', {'events': ['arrive_complete', 'cp_clear', 'offer', 'arrive_no_tail', 'cancel', 'depart', 'depart', 'arrive_complete', 'offer', 'cp_blocked']}, {'state': 'line_clear', 'alarms': ['tail-missing', 'unauthorised-departure', 'unauthorised-departure']}), ('sampled regression 1', {'events': ['cp_blocked', 'depart', 'arrive_no_tail', 'cp_clear', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure']}), ('boundary: offer with clearing point fouled', {'events': ['cp_blocked', 'offer', 'cp_clear', 'offer']}, {'state': 'line_clear', 'alarms': ['refused']}), ('control 4', {'events': ['cancel', 'arrive_no_tail', 'offer', 'offer', 'depart', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused', 'tail-missing']}), ('control 7', {'events': ['offer', 'arrive_no_tail', 'arrive_complete', 'cp_clear', 'cp_clear', 'arrive_no_tail']}, {'state': 'line_clear', 'alarms': ['tail-missing', 'tail-missing']}), ('control 10', {'events': ['arrive_complete', 'cp_blocked', 'offer', 'arrive_complete', 'depart']}, {'state': 'train_on_line', 'alarms': ['refused', 'unauthorised-departure']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 29', {'events': ['arrive_complete', 'depart', 'offer', 'depart', 'arrive_complete', 'arrive_no_tail', 'cp_clear']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']}), ('control 10', {'events': ['arrive_complete', 'cp_blocked', 'offer', 'arrive_complete', 'depart']}, {'state': 'train_on_line', 'alarms': ['refused', 'unauthorised-departure']}), ('boundary: train arrives without tail lamp', {'events': ['offer', 'depart', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused']}), ('control 12', {'events': ['depart', 'cp_clear', 'arrive_complete', 'depart', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'unauthorised-departure']}), ('control 15', {'events': ['arrive_complete', 'cp_clear', 'cancel']}, {'state': 'normal', 'alarms': []}), ('control 18', {'events': ['cp_clear', 'depart', 'offer', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 57', {'events': ['cp_blocked', 'depart', 'offer', 'cp_blocked', 'depart', 'arrive_no_tail', 'cancel', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']}), ('sampled regression 17', {'events': ['depart', 'arrive_complete', 'offer', 'arrive_complete', 'depart', 'offer', 'offer', 'depart', 'offer', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused', 'refused', 'unauthorised-departure', 'refused', 'tail-missing']}), ('boundary: train arrives without tail lamp', {'events': ['offer', 'depart', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused']}), ('control 23', {'events': ['depart', 'cp_blocked', 'arrive_no_tail', 'offer', 'cp_clear']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'refused']}), ('control 26', {'events': ['cp_clear', 'offer', 'cp_clear', 'cp_clear', 'cp_blocked', 'cp_clear', 'cp_blocked', 'depart']}, {'state': 'train_on_line', 'alarms': []}), ('sampled regression 29', {'events': ['arrive_complete', 'depart', 'offer', 'depart', 'arrive_complete', 'arrive_no_tail', 'cp_clear']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 78', {'events': ['cp_blocked', 'arrive_no_tail', 'depart', 'cancel', 'arrive_no_tail', 'depart']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'unauthorised-departure', 'tail-missing', 'unauthorised-departure']}), ('control 23', {'events': ['depart', 'cp_blocked', 'arrive_no_tail', 'offer', 'cp_clear']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'refused']}), ('boundary: cancel of line clear', {'events': ['offer', 'cancel', 'offer']}, {'state': 'line_clear', 'alarms': []}), ('control 34', {'events': ['cp_blocked', 'arrive_no_tail', 'cancel', 'cp_clear', 'offer', 'arrive_complete', 'cp_blocked']}, {'state': 'line_clear', 'alarms': ['tail-missing']}), ('control 37', {'events': ['offer', 'depart', 'cp_clear', 'cp_clear']}, {'state': 'train_on_line', 'alarms': []}), ('control 40', {'events': ['arrive_complete', 'cp_clear', 'arrive_no_tail']}, {'state': 'normal', 'alarms': ['tail-missing']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 16', {'events': ['arrive_complete', 'cp_blocked', 'depart', 'depart', 'offer', 'cp_clear', 'offer']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'unauthorised-departure', 'refused', 'refused']}), ('sampled regression 30', {'events': ['depart', 'arrive_no_tail', 'depart', 'depart', 'offer', 'depart', 'depart', 'cp_blocked', 'arrive_no_tail', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure', 'unauthorised-departure', 'refused', 'unauthorised-departure', 'unauthorised-departure', 'tail-missing', 'tail-missing']}), ('boundary: offer with clearing point fouled', {'events': ['cp_blocked', 'offer', 'cp_clear', 'offer']}, {'state': 'line_clear', 'alarms': ['refused']}), ('sampled regression 45', {'events': ['depart', 'depart', 'depart', 'cp_blocked', 'depart', 'offer', 'arrive_complete', 'offer']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'unauthorised-departure', 'unauthorised-departure', 'unauthorised-departure', 'refused', 'refused']}), ('control 48', {'events': ['cp_clear', 'cp_blocked', 'arrive_no_tail', 'depart', 'offer', 'offer', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'unauthorised-departure', 'refused', 'refused', 'tail-missing', 'refused']}), ('control 51', {'events': ['cp_clear', 'cp_blocked', 'offer']}, {'state': 'normal', 'alarms': ['refused']})]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: second train into occupied block | {'alarms': [], 'state': 'train_on_line'} | {'alarms': ['unauthorised-departure'], 'state': 'train_on_line'} | Failed |
| boundary: departure without offer | {'alarms': ['unauthorised-departure'], 'state': 'normal'} | {'alarms': ['unauthorised-departure'], 'state': 'normal'} | Passed |
| sampled regression 5 | {'alarms': ['tail-missing', 'unauthorised-departure'], 'state': 'line_clear'} | {'alarms': ['tail-missing', 'unauthorised-departure', 'unauthorised-departure'], 'state': 'line_clear'} | Failed |
| sampled regression 1 | {'alarms': ['unauthorised-departure', 'tail-missing'], 'state': 'train_on_line'} | {'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure'], 'state': 'train_on_line'} | Failed |
| boundary: offer with clearing point fouled | {'alarms': ['refused'], 'state': 'line_clear'} | {'alarms': ['refused'], 'state': 'line_clear'} | Passed |
| control 4 | {'alarms': ['tail-missing', 'refused', 'tail-missing'], 'state': 'train_on_line'} | {'alarms': ['tail-missing', 'refused', 'tail-missing'], 'state': 'train_on_line'} | Passed |
| control 7 | {'alarms': ['tail-missing', 'tail-missing'], 'state': 'line_clear'} | {'alarms': ['tail-missing', 'tail-missing'], 'state': 'line_clear'} | Passed |
| control 10 | {'alarms': ['refused', 'unauthorised-departure'], 'state': 'train_on_line'} | {'alarms': ['refused', 'unauthorised-departure'], 'state': 'train_on_line'} | Passed |
SHA-256 / 4af5728e8b7a385641b5cba1424fd22dacb0ca9e5790fb30d3c5ce8f63692278
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
state = 'normal'
cp = True
alarms = []
for ev in x['events']:
if ev == 'cp_blocked':
cp = False
elif ev == 'cp_clear':
cp = True
elif ev == 'offer':
if state == 'normal' and cp:
state = 'line_clear'
else:
alarms.append('refused')
elif ev == 'depart':
if state == 'train_on_line':
alarms.append('unauthorised-departure')
state = 'train_on_line'
elif ev == 'arrive_complete':
if state == 'train_on_line':
state = 'normal'
elif ev == 'arrive_no_tail':
alarms.append('tail-missing')
elif ev == 'cancel':
if state == 'line_clear':
state = 'normal'
return {'state': state, 'alarms': alarms}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 5', {'events': ['arrive_complete', 'cp_clear', 'offer', 'arrive_no_tail', 'cancel', 'depart', 'depart', 'arrive_complete', 'offer', 'cp_blocked']}, {'state': 'line_clear', 'alarms': ['tail-missing', 'unauthorised-departure', 'unauthorised-departure']}), ('sampled regression 1', {'events': ['cp_blocked', 'depart', 'arrive_no_tail', 'cp_clear', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure']}), ('boundary: offer with clearing point fouled', {'events': ['cp_blocked', 'offer', 'cp_clear', 'offer']}, {'state': 'line_clear', 'alarms': ['refused']}), ('control 4', {'events': ['cancel', 'arrive_no_tail', 'offer', 'offer', 'depart', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused', 'tail-missing']}), ('control 7', {'events': ['offer', 'arrive_no_tail', 'arrive_complete', 'cp_clear', 'cp_clear', 'arrive_no_tail']}, {'state': 'line_clear', 'alarms': ['tail-missing', 'tail-missing']}), ('control 10', {'events': ['arrive_complete', 'cp_blocked', 'offer', 'arrive_complete', 'depart']}, {'state': 'train_on_line', 'alarms': ['refused', 'unauthorised-departure']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 29', {'events': ['arrive_complete', 'depart', 'offer', 'depart', 'arrive_complete', 'arrive_no_tail', 'cp_clear']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']}), ('control 10', {'events': ['arrive_complete', 'cp_blocked', 'offer', 'arrive_complete', 'depart']}, {'state': 'train_on_line', 'alarms': ['refused', 'unauthorised-departure']}), ('boundary: train arrives without tail lamp', {'events': ['offer', 'depart', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused']}), ('control 12', {'events': ['depart', 'cp_clear', 'arrive_complete', 'depart', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'unauthorised-departure']}), ('control 15', {'events': ['arrive_complete', 'cp_clear', 'cancel']}, {'state': 'normal', 'alarms': []}), ('control 18', {'events': ['cp_clear', 'depart', 'offer', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 57', {'events': ['cp_blocked', 'depart', 'offer', 'cp_blocked', 'depart', 'arrive_no_tail', 'cancel', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']}), ('sampled regression 17', {'events': ['depart', 'arrive_complete', 'offer', 'arrive_complete', 'depart', 'offer', 'offer', 'depart', 'offer', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused', 'refused', 'unauthorised-departure', 'refused', 'tail-missing']}), ('boundary: train arrives without tail lamp', {'events': ['offer', 'depart', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused']}), ('control 23', {'events': ['depart', 'cp_blocked', 'arrive_no_tail', 'offer', 'cp_clear']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'refused']}), ('control 26', {'events': ['cp_clear', 'offer', 'cp_clear', 'cp_clear', 'cp_blocked', 'cp_clear', 'cp_blocked', 'depart']}, {'state': 'train_on_line', 'alarms': []}), ('sampled regression 29', {'events': ['arrive_complete', 'depart', 'offer', 'depart', 'arrive_complete', 'arrive_no_tail', 'cp_clear']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 78', {'events': ['cp_blocked', 'arrive_no_tail', 'depart', 'cancel', 'arrive_no_tail', 'depart']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'unauthorised-departure', 'tail-missing', 'unauthorised-departure']}), ('control 23', {'events': ['depart', 'cp_blocked', 'arrive_no_tail', 'offer', 'cp_clear']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'refused']}), ('boundary: cancel of line clear', {'events': ['offer', 'cancel', 'offer']}, {'state': 'line_clear', 'alarms': []}), ('control 34', {'events': ['cp_blocked', 'arrive_no_tail', 'cancel', 'cp_clear', 'offer', 'arrive_complete', 'cp_blocked']}, {'state': 'line_clear', 'alarms': ['tail-missing']}), ('control 37', {'events': ['offer', 'depart', 'cp_clear', 'cp_clear']}, {'state': 'train_on_line', 'alarms': []}), ('control 40', {'events': ['arrive_complete', 'cp_clear', 'arrive_no_tail']}, {'state': 'normal', 'alarms': ['tail-missing']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 16', {'events': ['arrive_complete', 'cp_blocked', 'depart', 'depart', 'offer', 'cp_clear', 'offer']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'unauthorised-departure', 'refused', 'refused']}), ('sampled regression 30', {'events': ['depart', 'arrive_no_tail', 'depart', 'depart', 'offer', 'depart', 'depart', 'cp_blocked', 'arrive_no_tail', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure', 'unauthorised-departure', 'refused', 'unauthorised-departure', 'unauthorised-departure', 'tail-missing', 'tail-missing']}), ('boundary: offer with clearing point fouled', {'events': ['cp_blocked', 'offer', 'cp_clear', 'offer']}, {'state': 'line_clear', 'alarms': ['refused']}), ('sampled regression 45', {'events': ['depart', 'depart', 'depart', 'cp_blocked', 'depart', 'offer', 'arrive_complete', 'offer']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'unauthorised-departure', 'unauthorised-departure', 'unauthorised-departure', 'refused', 'refused']}), ('control 48', {'events': ['cp_clear', 'cp_blocked', 'arrive_no_tail', 'depart', 'offer', 'offer', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'unauthorised-departure', 'refused', 'refused', 'tail-missing', 'refused']}), ('control 51', {'events': ['cp_clear', 'cp_blocked', 'offer']}, {'state': 'normal', 'alarms': ['refused']})]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: second train into occupied block | {'alarms': ['unauthorised-departure'], 'state': 'train_on_line'} | {'alarms': ['unauthorised-departure'], 'state': 'train_on_line'} | Passed |
| boundary: departure without offer | {'alarms': [], 'state': 'normal'} | {'alarms': ['unauthorised-departure'], 'state': 'normal'} | Failed |
| sampled regression 5 | {'alarms': ['tail-missing', 'unauthorised-departure'], 'state': 'line_clear'} | {'alarms': ['tail-missing', 'unauthorised-departure', 'unauthorised-departure'], 'state': 'line_clear'} | Failed |
| sampled regression 1 | {'alarms': ['tail-missing', 'unauthorised-departure'], 'state': 'train_on_line'} | {'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure'], 'state': 'train_on_line'} | Failed |
| boundary: offer with clearing point fouled | {'alarms': ['refused'], 'state': 'line_clear'} | {'alarms': ['refused'], 'state': 'line_clear'} | Passed |
| control 4 | {'alarms': ['tail-missing', 'refused', 'tail-missing'], 'state': 'train_on_line'} | {'alarms': ['tail-missing', 'refused', 'tail-missing'], 'state': 'train_on_line'} | Passed |
| control 7 | {'alarms': ['tail-missing', 'tail-missing'], 'state': 'line_clear'} | {'alarms': ['tail-missing', 'tail-missing'], 'state': 'line_clear'} | Passed |
| control 10 | {'alarms': ['refused'], 'state': 'train_on_line'} | {'alarms': ['refused', 'unauthorised-departure'], 'state': 'train_on_line'} | Failed |
SHA-256 / 4a675d4e1f5074ce63e7e33513c28e8ab5443c96696c631b9f0465878959dd3c
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
state = 'normal'
cp = True
alarms = []
for ev in x['events']:
if ev == 'cp_blocked':
cp = False
elif ev == 'cp_clear':
cp = True
elif ev == 'offer':
if state == 'normal' and cp:
state = 'line_clear'
else:
alarms.append('refused')
elif ev == 'depart':
if state != 'line_clear':
alarms.append('unauthorised-departure')
state = 'train_on_line'
elif ev == 'arrive_complete':
if state == 'train_on_line':
state = 'normal'
elif ev == 'arrive_no_tail':
alarms.append('tail-missing')
elif ev == 'cancel':
if state == 'line_clear':
state = 'normal'
return {'state': state, 'alarms': alarms}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 5', {'events': ['arrive_complete', 'cp_clear', 'offer', 'arrive_no_tail', 'cancel', 'depart', 'depart', 'arrive_complete', 'offer', 'cp_blocked']}, {'state': 'line_clear', 'alarms': ['tail-missing', 'unauthorised-departure', 'unauthorised-departure']}), ('sampled regression 1', {'events': ['cp_blocked', 'depart', 'arrive_no_tail', 'cp_clear', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure']}), ('boundary: offer with clearing point fouled', {'events': ['cp_blocked', 'offer', 'cp_clear', 'offer']}, {'state': 'line_clear', 'alarms': ['refused']}), ('control 4', {'events': ['cancel', 'arrive_no_tail', 'offer', 'offer', 'depart', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused', 'tail-missing']}), ('control 7', {'events': ['offer', 'arrive_no_tail', 'arrive_complete', 'cp_clear', 'cp_clear', 'arrive_no_tail']}, {'state': 'line_clear', 'alarms': ['tail-missing', 'tail-missing']}), ('control 10', {'events': ['arrive_complete', 'cp_blocked', 'offer', 'arrive_complete', 'depart']}, {'state': 'train_on_line', 'alarms': ['refused', 'unauthorised-departure']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 29', {'events': ['arrive_complete', 'depart', 'offer', 'depart', 'arrive_complete', 'arrive_no_tail', 'cp_clear']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']}), ('control 10', {'events': ['arrive_complete', 'cp_blocked', 'offer', 'arrive_complete', 'depart']}, {'state': 'train_on_line', 'alarms': ['refused', 'unauthorised-departure']}), ('boundary: train arrives without tail lamp', {'events': ['offer', 'depart', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused']}), ('control 12', {'events': ['depart', 'cp_clear', 'arrive_complete', 'depart', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'unauthorised-departure']}), ('control 15', {'events': ['arrive_complete', 'cp_clear', 'cancel']}, {'state': 'normal', 'alarms': []}), ('control 18', {'events': ['cp_clear', 'depart', 'offer', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 57', {'events': ['cp_blocked', 'depart', 'offer', 'cp_blocked', 'depart', 'arrive_no_tail', 'cancel', 'cp_blocked']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']}), ('sampled regression 17', {'events': ['depart', 'arrive_complete', 'offer', 'arrive_complete', 'depart', 'offer', 'offer', 'depart', 'offer', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'refused', 'refused', 'unauthorised-departure', 'refused', 'tail-missing']}), ('boundary: train arrives without tail lamp', {'events': ['offer', 'depart', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'refused']}), ('control 23', {'events': ['depart', 'cp_blocked', 'arrive_no_tail', 'offer', 'cp_clear']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'refused']}), ('control 26', {'events': ['cp_clear', 'offer', 'cp_clear', 'cp_clear', 'cp_blocked', 'cp_clear', 'cp_blocked', 'depart']}, {'state': 'train_on_line', 'alarms': []}), ('sampled regression 29', {'events': ['arrive_complete', 'depart', 'offer', 'depart', 'arrive_complete', 'arrive_no_tail', 'cp_clear']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'refused', 'unauthorised-departure', 'tail-missing']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 78', {'events': ['cp_blocked', 'arrive_no_tail', 'depart', 'cancel', 'arrive_no_tail', 'depart']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'unauthorised-departure', 'tail-missing', 'unauthorised-departure']}), ('control 23', {'events': ['depart', 'cp_blocked', 'arrive_no_tail', 'offer', 'cp_clear']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'refused']}), ('boundary: cancel of line clear', {'events': ['offer', 'cancel', 'offer']}, {'state': 'line_clear', 'alarms': []}), ('control 34', {'events': ['cp_blocked', 'arrive_no_tail', 'cancel', 'cp_clear', 'offer', 'arrive_complete', 'cp_blocked']}, {'state': 'line_clear', 'alarms': ['tail-missing']}), ('control 37', {'events': ['offer', 'depart', 'cp_clear', 'cp_clear']}, {'state': 'train_on_line', 'alarms': []}), ('control 40', {'events': ['arrive_complete', 'cp_clear', 'arrive_no_tail']}, {'state': 'normal', 'alarms': ['tail-missing']})], [('regression: second train into occupied block', {'events': ['offer', 'depart', 'depart']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure']}), ('boundary: departure without offer', {'events': ['depart', 'arrive_complete']}, {'state': 'normal', 'alarms': ['unauthorised-departure']}), ('sampled regression 16', {'events': ['arrive_complete', 'cp_blocked', 'depart', 'depart', 'offer', 'cp_clear', 'offer']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'unauthorised-departure', 'refused', 'refused']}), ('sampled regression 30', {'events': ['depart', 'arrive_no_tail', 'depart', 'depart', 'offer', 'depart', 'depart', 'cp_blocked', 'arrive_no_tail', 'arrive_no_tail']}, {'state': 'train_on_line', 'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure', 'unauthorised-departure', 'refused', 'unauthorised-departure', 'unauthorised-departure', 'tail-missing', 'tail-missing']}), ('boundary: offer with clearing point fouled', {'events': ['cp_blocked', 'offer', 'cp_clear', 'offer']}, {'state': 'line_clear', 'alarms': ['refused']}), ('sampled regression 45', {'events': ['depart', 'depart', 'depart', 'cp_blocked', 'depart', 'offer', 'arrive_complete', 'offer']}, {'state': 'normal', 'alarms': ['unauthorised-departure', 'unauthorised-departure', 'unauthorised-departure', 'unauthorised-departure', 'refused', 'refused']}), ('control 48', {'events': ['cp_clear', 'cp_blocked', 'arrive_no_tail', 'depart', 'offer', 'offer', 'arrive_no_tail', 'offer']}, {'state': 'train_on_line', 'alarms': ['tail-missing', 'unauthorised-departure', 'refused', 'refused', 'tail-missing', 'refused']}), ('control 51', {'events': ['cp_clear', 'cp_blocked', 'offer']}, {'state': 'normal', 'alarms': ['refused']})]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: second train into occupied block | {'alarms': ['unauthorised-departure'], 'state': 'train_on_line'} | {'alarms': ['unauthorised-departure'], 'state': 'train_on_line'} | Passed |
| boundary: departure without offer | {'alarms': ['unauthorised-departure'], 'state': 'normal'} | {'alarms': ['unauthorised-departure'], 'state': 'normal'} | Passed |
| sampled regression 5 | {'alarms': ['tail-missing', 'unauthorised-departure', 'unauthorised-departure'], 'state': 'line_clear'} | {'alarms': ['tail-missing', 'unauthorised-departure', 'unauthorised-departure'], 'state': 'line_clear'} | Passed |
| sampled regression 1 | {'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure'], 'state': 'train_on_line'} | {'alarms': ['unauthorised-departure', 'tail-missing', 'unauthorised-departure'], 'state': 'train_on_line'} | Passed |
| boundary: offer with clearing point fouled | {'alarms': ['refused'], 'state': 'line_clear'} | {'alarms': ['refused'], 'state': 'line_clear'} | Passed |
| control 4 | {'alarms': ['tail-missing', 'refused', 'tail-missing'], 'state': 'train_on_line'} | {'alarms': ['tail-missing', 'refused', 'tail-missing'], 'state': 'train_on_line'} | Passed |
| control 7 | {'alarms': ['tail-missing', 'tail-missing'], 'state': 'line_clear'} | {'alarms': ['tail-missing', 'tail-missing'], 'state': 'line_clear'} | Passed |
| control 10 | {'alarms': ['refused', 'unauthorised-departure'], 'state': 'train_on_line'} | {'alarms': ['refused', 'unauthorised-departure'], 'state': 'train_on_line'} | Passed |
SHA-256 / 1b0d9e16406f2828549f90713eadb112e650e90816e2e9408f1cb1002408aea2
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:49.272898+00:00.
Case digest / a20761a1967a5e8aa0575a03a4a386a24b622d3a0fa9b06add1522ec0ccb347e