FA-67201 / Railway interlocking logic / Open access
Call-on permissive move authorisation: standing time boundary · case 01
A train that has stood exactly two minutes is refused the call-on.
ROOT CAUSE
The standing-time comparison is inclusive.
VERIFIED REPAIR
Refuse only when the train has stood less than 120 s.
Unsuccessful approach: Comparing seconds against a threshold of 2 treats the limit as minutes and admits trains that barely stopped.
Case contract
Without a route the answer is none. With the section ahead clear the main aspect is given. Into an occupied section a call-on is given only if the train has stood at the signal for at least 120 s and is stationary (0 km/h), the gap to the standing train is at least 20 m and that train is not moving; otherwise none.
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):
if not x['route_set']:
return 'none'
if not x['ahead_occupied']:
return 'main'
if x['stand_s'] <= 120 or x['speed_kmh'] > 0:
return 'none'
if x['gap_m'] < 20:
return 'none'
if x['platform_train_moving']:
return 'none'
return 'call-on'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('control 27', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 1', {'route_set': True, 'ahead_occupied': False, 'stand_s': 300, 'speed_kmh': 0, 'gap_m': 60, 'platform_train_moving': False}, 'main'), ('control 4', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 3, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 7', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 3, 'gap_m': 19, 'platform_train_moving': False}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: rolling at call-on speed', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 12, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: platform train moving far away', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 12', {'route_set': True, 'ahead_occupied': True, 'stand_s': 300, 'speed_kmh': 0, 'gap_m': 5, 'platform_train_moving': False}, 'none'), ('control 15', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': True}, 'none'), ('control 18', {'route_set': True, 'ahead_occupied': True, 'stand_s': 0, 'speed_kmh': 0, 'gap_m': 20, 'platform_train_moving': True}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('control 80', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 21, 'platform_train_moving': False}, 'none'), ('boundary: platform train moving far away', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 23', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 15, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('control 26', {'route_set': False, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 19, 'platform_train_moving': False}, 'none'), ('control 29', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': False}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 27', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('boundary: gap exactly at the minimum', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 20, 'platform_train_moving': False}, 'call-on'), ('boundary: clear platform for a moving train', {'route_set': True, 'ahead_occupied': False, 'stand_s': 0, 'speed_kmh': 40, 'gap_m': 100, 'platform_train_moving': False}, 'main'), ('control 34', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 20, 'gap_m': 60, 'platform_train_moving': False}, 'none'), ('control 37', {'route_set': True, 'ahead_occupied': True, 'stand_s': 0, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': False}, 'none'), ('control 40', {'route_set': True, 'ahead_occupied': True, 'stand_s': 121, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('boundary: no route', {'route_set': False, 'ahead_occupied': False, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 45', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 5, 'platform_train_moving': False}, 'none'), ('control 48', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 20, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('control 51', {'route_set': True, 'ahead_occupied': False, 'stand_s': 300, 'speed_kmh': 3, 'gap_m': 20, 'platform_train_moving': False}, 'main')]]
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: stood exactly two minutes | none | call-on | Failed |
| boundary: stood one second short | none | none | Passed |
| sampled regression 70 | none | call-on | Failed |
| control 27 | none | none | Passed |
| boundary: creeping at walking pace | none | none | Passed |
| control 1 | main | main | Passed |
| control 4 | none | none | Passed |
| control 7 | none | none | Passed |
SHA-256 / 3c0f5cd7149dd126f6185b5048c38f2bae5d8022aeeb5ec60be604b329040398
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if not x['route_set']:
return 'none'
if not x['ahead_occupied']:
return 'main'
if x['stand_s'] < 2 or x['speed_kmh'] > 0:
return 'none'
if x['gap_m'] < 20:
return 'none'
if x['platform_train_moving']:
return 'none'
return 'call-on'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('control 27', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 1', {'route_set': True, 'ahead_occupied': False, 'stand_s': 300, 'speed_kmh': 0, 'gap_m': 60, 'platform_train_moving': False}, 'main'), ('control 4', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 3, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 7', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 3, 'gap_m': 19, 'platform_train_moving': False}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: rolling at call-on speed', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 12, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: platform train moving far away', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 12', {'route_set': True, 'ahead_occupied': True, 'stand_s': 300, 'speed_kmh': 0, 'gap_m': 5, 'platform_train_moving': False}, 'none'), ('control 15', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': True}, 'none'), ('control 18', {'route_set': True, 'ahead_occupied': True, 'stand_s': 0, 'speed_kmh': 0, 'gap_m': 20, 'platform_train_moving': True}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('control 80', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 21, 'platform_train_moving': False}, 'none'), ('boundary: platform train moving far away', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 23', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 15, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('control 26', {'route_set': False, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 19, 'platform_train_moving': False}, 'none'), ('control 29', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': False}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 27', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('boundary: gap exactly at the minimum', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 20, 'platform_train_moving': False}, 'call-on'), ('boundary: clear platform for a moving train', {'route_set': True, 'ahead_occupied': False, 'stand_s': 0, 'speed_kmh': 40, 'gap_m': 100, 'platform_train_moving': False}, 'main'), ('control 34', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 20, 'gap_m': 60, 'platform_train_moving': False}, 'none'), ('control 37', {'route_set': True, 'ahead_occupied': True, 'stand_s': 0, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': False}, 'none'), ('control 40', {'route_set': True, 'ahead_occupied': True, 'stand_s': 121, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('boundary: no route', {'route_set': False, 'ahead_occupied': False, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 45', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 5, 'platform_train_moving': False}, 'none'), ('control 48', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 20, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('control 51', {'route_set': True, 'ahead_occupied': False, 'stand_s': 300, 'speed_kmh': 3, 'gap_m': 20, 'platform_train_moving': False}, 'main')]]
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: stood exactly two minutes | call-on | call-on | Passed |
| boundary: stood one second short | call-on | none | Failed |
| sampled regression 70 | call-on | call-on | Passed |
| control 27 | call-on | none | Failed |
| boundary: creeping at walking pace | none | none | Passed |
| control 1 | main | main | Passed |
| control 4 | none | none | Passed |
| control 7 | none | none | Passed |
SHA-256 / e9beeb2c4905b6038998975b25523d9755d34316f5ea0449d311dc36e7c0ff94
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if not x['route_set']:
return 'none'
if not x['ahead_occupied']:
return 'main'
if x['stand_s'] < 120 or x['speed_kmh'] > 0:
return 'none'
if x['gap_m'] < 20:
return 'none'
if x['platform_train_moving']:
return 'none'
return 'call-on'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('control 27', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 1', {'route_set': True, 'ahead_occupied': False, 'stand_s': 300, 'speed_kmh': 0, 'gap_m': 60, 'platform_train_moving': False}, 'main'), ('control 4', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 3, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 7', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 3, 'gap_m': 19, 'platform_train_moving': False}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: rolling at call-on speed', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 12, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: platform train moving far away', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 12', {'route_set': True, 'ahead_occupied': True, 'stand_s': 300, 'speed_kmh': 0, 'gap_m': 5, 'platform_train_moving': False}, 'none'), ('control 15', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': True}, 'none'), ('control 18', {'route_set': True, 'ahead_occupied': True, 'stand_s': 0, 'speed_kmh': 0, 'gap_m': 20, 'platform_train_moving': True}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('control 80', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 21, 'platform_train_moving': False}, 'none'), ('boundary: platform train moving far away', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': True}, 'none'), ('control 23', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 15, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('control 26', {'route_set': False, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 19, 'platform_train_moving': False}, 'none'), ('control 29', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': False}, 'none')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 27', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('boundary: gap exactly at the minimum', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 20, 'platform_train_moving': False}, 'call-on'), ('boundary: clear platform for a moving train', {'route_set': True, 'ahead_occupied': False, 'stand_s': 0, 'speed_kmh': 40, 'gap_m': 100, 'platform_train_moving': False}, 'main'), ('control 34', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 20, 'gap_m': 60, 'platform_train_moving': False}, 'none'), ('control 37', {'route_set': True, 'ahead_occupied': True, 'stand_s': 0, 'speed_kmh': 20, 'gap_m': 19, 'platform_train_moving': False}, 'none'), ('control 40', {'route_set': True, 'ahead_occupied': True, 'stand_s': 121, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on')], [('regression: stood exactly two minutes', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'call-on'), ('boundary: stood one second short', {'route_set': True, 'ahead_occupied': True, 'stand_s': 119, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('sampled regression 70', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 200, 'platform_train_moving': False}, 'call-on'), ('boundary: no route', {'route_set': False, 'ahead_occupied': False, 'stand_s': 200, 'speed_kmh': 0, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('boundary: creeping at walking pace', {'route_set': True, 'ahead_occupied': True, 'stand_s': 200, 'speed_kmh': 3, 'gap_m': 100, 'platform_train_moving': False}, 'none'), ('control 45', {'route_set': True, 'ahead_occupied': True, 'stand_s': 120, 'speed_kmh': 0, 'gap_m': 5, 'platform_train_moving': False}, 'none'), ('control 48', {'route_set': True, 'ahead_occupied': True, 'stand_s': 30, 'speed_kmh': 20, 'gap_m': 200, 'platform_train_moving': False}, 'none'), ('control 51', {'route_set': True, 'ahead_occupied': False, 'stand_s': 300, 'speed_kmh': 3, 'gap_m': 20, 'platform_train_moving': False}, 'main')]]
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: stood exactly two minutes | call-on | call-on | Passed |
| boundary: stood one second short | none | none | Passed |
| sampled regression 70 | call-on | call-on | Passed |
| control 27 | none | none | Passed |
| boundary: creeping at walking pace | none | none | Passed |
| control 1 | main | main | Passed |
| control 4 | none | none | Passed |
| control 7 | none | none | Passed |
SHA-256 / 184fc20f84a3696e85a03b6c697029776460b006ba9c01e9bf81df4ffa8a700f
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:50.664814+00:00.
Case digest / ae81b1b4dec128e532952f8bc217928b5ae8c4d69e4d3f8f77b13fc266d28c3c