FA-67176 / Railway interlocking logic / Open access
Signal replacement and stick control: replacement stick latch · case 01
A signal re-clears behind a train for a following train on the same route setting.
ROOT CAUSE
A train passing a clear signal never latches the stick.
VERIFIED REPAIR
Latch the stick whenever a clear signal is passed.
Unsuccessful approach: Latching only for controlled signals lets approach-released signals re-clear behind the train.
Case contract
Each step gives [section beyond occupied, route set, approach occupied]. An auto signal behaves as permanently routed. A signal shows danger whenever the section beyond is occupied; a signal that was clear when a train occupies that section latches a stick that keeps it at danger until the route is set afresh (off then on); auto signals drop the stick every step. Otherwise it clears when routed, not stuck, and for approach-released signals only with the approach occupied. Output the state per step.
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):
mode = x['mode']
state = 'danger'
stick = False
prev_route = False
out = []
for occ, route, appr in x['steps']:
if mode == 'auto':
route = True
if (route and not prev_route) or mode == 'auto':
stick = False
if occ:
pass
state = 'danger'
elif route and not stick and (mode != 'approach' or appr):
state = 'clear'
else:
state = 'danger'
prev_route = route
out.append(state)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 5', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True], [False, True, True], [True, True, False], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('control 1', {'mode': 'auto', 'steps': [[False, True, False], [False, False, True], [False, True, False], [False, False, True], [False, False, False]]}, ['clear', 'clear', 'clear', 'clear', 'clear']), ('sampled regression 4', {'mode': 'controlled', 'steps': [[False, False, False], [False, True, True], [True, True, True], [False, True, True], [False, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger']), ('control 7', {'mode': 'approach', 'steps': [[False, False, False], [False, False, False], [False, False, True], [False, False, True], [False, True, False], [False, False, True], [False, True, True], [False, True, True], [False, True, True], [True, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'])], [('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 64', {'mode': 'approach', 'steps': [[True, True, True], [False, False, True], [False, True, True], [True, True, True], [True, True, False], [False, True, False], [False, True, False], [False, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('sampled regression 50', {'mode': 'approach', 'steps': [[True, True, True], [False, True, True], [True, True, False], [True, True, False], [False, True, True], [False, False, False], [False, False, False], [True, False, True], [False, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('boundary: automatic signal re-clears', {'mode': 'auto', 'steps': [[False, False, False], [True, False, True], [False, False, False]]}, ['clear', 'danger', 'clear']), ('control 12', {'mode': 'controlled', 'steps': [[False, False, True], [False, True, True], [True, False, True], [False, False, False], [False, False, True], [True, True, True], [True, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 15', {'mode': 'approach', 'steps': [[False, True, True], [False, True, False], [False, True, True]]}, ['clear', 'danger', 'clear']), ('control 18', {'mode': 'approach', 'steps': [[False, True, False], [False, False, False], [False, False, False], [True, True, False], [False, True, False], [True, True, True], [False, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear'])], [('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 19', {'mode': 'controlled', 'steps': [[True, False, False], [False, False, True], [True, True, True], [False, False, True], [False, False, True], [False, True, True], [True, True, True], [False, True, False]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'danger', 'danger']), ('sampled regression 64', {'mode': 'approach', 'steps': [[True, True, True], [False, False, True], [False, True, True], [True, True, True], [True, True, False], [False, True, False], [False, True, False], [False, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('boundary: automatic signal re-clears', {'mode': 'auto', 'steps': [[False, False, False], [True, False, True], [False, False, False]]}, ['clear', 'danger', 'clear']), ('sampled regression 23', {'mode': 'controlled', 'steps': [[False, True, True], [False, True, False], [False, True, True], [True, True, False], [False, True, False]]}, ['clear', 'clear', 'clear', 'danger', 'danger']), ('control 26', {'mode': 'approach', 'steps': [[False, False, False], [False, True, True], [True, True, False], [True, False, True], [True, True, False], [True, False, True], [False, False, False], [False, True, True], [False, False, True], [False, True, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'danger', 'danger']), ('control 29', {'mode': 'auto', 'steps': [[True, False, False], [False, False, False], [True, False, False], [False, False, True], [False, False, False], [False, True, True], [False, True, True], [False, False, False], [True, False, True], [False, True, False]]}, ['danger', 'clear', 'danger', 'clear', 'clear', 'clear', 'clear', 'clear', 'danger', 'clear'])], [('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('boundary: controlled signal with a standing train', {'mode': 'controlled', 'steps': [[True, True, True], [False, True, True]]}, ['danger', 'clear']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('control 34', {'mode': 'approach', 'steps': [[False, True, True], [False, False, False], [False, True, True], [False, False, False], [True, False, True], [False, False, True], [True, False, False], [True, False, True]]}, ['clear', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 37', {'mode': 'approach', 'steps': [[False, False, True], [True, False, False], [False, False, True], [False, False, True], [True, False, True], [False, False, False], [False, False, True], [False, False, True], [False, False, False]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 40', {'mode': 'auto', 'steps': [[False, True, True], [True, True, True], [False, True, True], [False, True, False], [True, False, True], [True, False, True], [True, False, True]]}, ['clear', 'danger', 'clear', 'clear', 'danger', 'danger', 'danger'])], [('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 24', {'mode': 'controlled', 'steps': [[False, False, True], [False, False, True], [False, True, False], [False, True, True], [False, True, True], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'clear', 'clear', 'danger', 'danger', 'danger']), ('sampled regression 5', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True], [False, True, True], [True, True, False], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('control 45', {'mode': 'approach', 'steps': [[False, False, False], [False, False, False], [False, True, False], [False, True, False], [True, True, False], [False, True, False], [False, True, False], [False, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear']), ('control 48', {'mode': 'approach', 'steps': [[True, True, False], [False, True, True], [False, False, False], [False, False, True], [False, True, True], [True, True, False]]}, ['danger', 'clear', 'danger', 'danger', 'clear', 'danger']), ('control 51', {'mode': 'controlled', 'steps': [[False, False, True], [False, False, False], [False, True, False], [False, True, True], [True, False, True], [False, False, True], [True, True, False]]}, ['danger', 'danger', 'clear', 'clear', 'danger', 'danger', 'danger'])]]
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 behind on the same route | ['clear', 'danger', 'clear'] | ['clear', 'danger', 'danger'] | Failed |
| regression: approach-released signal replaced by train | ['clear', 'danger', 'clear'] | ['clear', 'danger', 'danger'] | Failed |
| sampled regression 5 | ['danger', 'clear', 'clear', 'danger', 'danger', 'clear', 'clear'] | ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger'] | Failed |
| boundary: route re-set after a train | ['clear', 'danger', 'danger', 'clear'] | ['clear', 'danger', 'danger', 'clear'] | Passed |
| boundary: approach-released signal with empty approach | ['danger', 'clear'] | ['danger', 'clear'] | Passed |
| control 1 | ['clear', 'clear', 'clear', 'clear', 'clear'] | ['clear', 'clear', 'clear', 'clear', 'clear'] | Passed |
| sampled regression 4 | ['danger', 'clear', 'danger', 'clear', 'danger'] | ['danger', 'clear', 'danger', 'danger', 'danger'] | Failed |
| control 7 | ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'] | ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'] | Passed |
SHA-256 / 400b72490bd4c6cd3962f647cb9f8cf2ba30c39a537926d2b3fa83422018168b
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
mode = x['mode']
state = 'danger'
stick = False
prev_route = False
out = []
for occ, route, appr in x['steps']:
if mode == 'auto':
route = True
if (route and not prev_route) or mode == 'auto':
stick = False
if occ:
if state == 'clear' and mode == 'controlled':
stick = True
state = 'danger'
elif route and not stick and (mode != 'approach' or appr):
state = 'clear'
else:
state = 'danger'
prev_route = route
out.append(state)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 5', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True], [False, True, True], [True, True, False], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('control 1', {'mode': 'auto', 'steps': [[False, True, False], [False, False, True], [False, True, False], [False, False, True], [False, False, False]]}, ['clear', 'clear', 'clear', 'clear', 'clear']), ('sampled regression 4', {'mode': 'controlled', 'steps': [[False, False, False], [False, True, True], [True, True, True], [False, True, True], [False, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger']), ('control 7', {'mode': 'approach', 'steps': [[False, False, False], [False, False, False], [False, False, True], [False, False, True], [False, True, False], [False, False, True], [False, True, True], [False, True, True], [False, True, True], [True, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'])], [('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 64', {'mode': 'approach', 'steps': [[True, True, True], [False, False, True], [False, True, True], [True, True, True], [True, True, False], [False, True, False], [False, True, False], [False, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('sampled regression 50', {'mode': 'approach', 'steps': [[True, True, True], [False, True, True], [True, True, False], [True, True, False], [False, True, True], [False, False, False], [False, False, False], [True, False, True], [False, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('boundary: automatic signal re-clears', {'mode': 'auto', 'steps': [[False, False, False], [True, False, True], [False, False, False]]}, ['clear', 'danger', 'clear']), ('control 12', {'mode': 'controlled', 'steps': [[False, False, True], [False, True, True], [True, False, True], [False, False, False], [False, False, True], [True, True, True], [True, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 15', {'mode': 'approach', 'steps': [[False, True, True], [False, True, False], [False, True, True]]}, ['clear', 'danger', 'clear']), ('control 18', {'mode': 'approach', 'steps': [[False, True, False], [False, False, False], [False, False, False], [True, True, False], [False, True, False], [True, True, True], [False, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear'])], [('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 19', {'mode': 'controlled', 'steps': [[True, False, False], [False, False, True], [True, True, True], [False, False, True], [False, False, True], [False, True, True], [True, True, True], [False, True, False]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'danger', 'danger']), ('sampled regression 64', {'mode': 'approach', 'steps': [[True, True, True], [False, False, True], [False, True, True], [True, True, True], [True, True, False], [False, True, False], [False, True, False], [False, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('boundary: automatic signal re-clears', {'mode': 'auto', 'steps': [[False, False, False], [True, False, True], [False, False, False]]}, ['clear', 'danger', 'clear']), ('sampled regression 23', {'mode': 'controlled', 'steps': [[False, True, True], [False, True, False], [False, True, True], [True, True, False], [False, True, False]]}, ['clear', 'clear', 'clear', 'danger', 'danger']), ('control 26', {'mode': 'approach', 'steps': [[False, False, False], [False, True, True], [True, True, False], [True, False, True], [True, True, False], [True, False, True], [False, False, False], [False, True, True], [False, False, True], [False, True, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'danger', 'danger']), ('control 29', {'mode': 'auto', 'steps': [[True, False, False], [False, False, False], [True, False, False], [False, False, True], [False, False, False], [False, True, True], [False, True, True], [False, False, False], [True, False, True], [False, True, False]]}, ['danger', 'clear', 'danger', 'clear', 'clear', 'clear', 'clear', 'clear', 'danger', 'clear'])], [('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('boundary: controlled signal with a standing train', {'mode': 'controlled', 'steps': [[True, True, True], [False, True, True]]}, ['danger', 'clear']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('control 34', {'mode': 'approach', 'steps': [[False, True, True], [False, False, False], [False, True, True], [False, False, False], [True, False, True], [False, False, True], [True, False, False], [True, False, True]]}, ['clear', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 37', {'mode': 'approach', 'steps': [[False, False, True], [True, False, False], [False, False, True], [False, False, True], [True, False, True], [False, False, False], [False, False, True], [False, False, True], [False, False, False]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 40', {'mode': 'auto', 'steps': [[False, True, True], [True, True, True], [False, True, True], [False, True, False], [True, False, True], [True, False, True], [True, False, True]]}, ['clear', 'danger', 'clear', 'clear', 'danger', 'danger', 'danger'])], [('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 24', {'mode': 'controlled', 'steps': [[False, False, True], [False, False, True], [False, True, False], [False, True, True], [False, True, True], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'clear', 'clear', 'danger', 'danger', 'danger']), ('sampled regression 5', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True], [False, True, True], [True, True, False], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('control 45', {'mode': 'approach', 'steps': [[False, False, False], [False, False, False], [False, True, False], [False, True, False], [True, True, False], [False, True, False], [False, True, False], [False, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear']), ('control 48', {'mode': 'approach', 'steps': [[True, True, False], [False, True, True], [False, False, False], [False, False, True], [False, True, True], [True, True, False]]}, ['danger', 'clear', 'danger', 'danger', 'clear', 'danger']), ('control 51', {'mode': 'controlled', 'steps': [[False, False, True], [False, False, False], [False, True, False], [False, True, True], [True, False, True], [False, False, True], [True, True, False]]}, ['danger', 'danger', 'clear', 'clear', 'danger', 'danger', 'danger'])]]
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 behind on the same route | ['clear', 'danger', 'danger'] | ['clear', 'danger', 'danger'] | Passed |
| regression: approach-released signal replaced by train | ['clear', 'danger', 'clear'] | ['clear', 'danger', 'danger'] | Failed |
| sampled regression 5 | ['danger', 'clear', 'clear', 'danger', 'danger', 'clear', 'clear'] | ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger'] | Failed |
| boundary: route re-set after a train | ['clear', 'danger', 'danger', 'clear'] | ['clear', 'danger', 'danger', 'clear'] | Passed |
| boundary: approach-released signal with empty approach | ['danger', 'clear'] | ['danger', 'clear'] | Passed |
| control 1 | ['clear', 'clear', 'clear', 'clear', 'clear'] | ['clear', 'clear', 'clear', 'clear', 'clear'] | Passed |
| sampled regression 4 | ['danger', 'clear', 'danger', 'danger', 'danger'] | ['danger', 'clear', 'danger', 'danger', 'danger'] | Passed |
| control 7 | ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'] | ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'] | Passed |
SHA-256 / dcc0b1ed2ef58cd1cd10038abbae0f6c8cf1ecf4555bd2b1ea9cfce8bfa179d6
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
mode = x['mode']
state = 'danger'
stick = False
prev_route = False
out = []
for occ, route, appr in x['steps']:
if mode == 'auto':
route = True
if (route and not prev_route) or mode == 'auto':
stick = False
if occ:
if state == 'clear':
stick = True
state = 'danger'
elif route and not stick and (mode != 'approach' or appr):
state = 'clear'
else:
state = 'danger'
prev_route = route
out.append(state)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 5', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True], [False, True, True], [True, True, False], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('control 1', {'mode': 'auto', 'steps': [[False, True, False], [False, False, True], [False, True, False], [False, False, True], [False, False, False]]}, ['clear', 'clear', 'clear', 'clear', 'clear']), ('sampled regression 4', {'mode': 'controlled', 'steps': [[False, False, False], [False, True, True], [True, True, True], [False, True, True], [False, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger']), ('control 7', {'mode': 'approach', 'steps': [[False, False, False], [False, False, False], [False, False, True], [False, False, True], [False, True, False], [False, False, True], [False, True, True], [False, True, True], [False, True, True], [True, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'])], [('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 64', {'mode': 'approach', 'steps': [[True, True, True], [False, False, True], [False, True, True], [True, True, True], [True, True, False], [False, True, False], [False, True, False], [False, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('sampled regression 50', {'mode': 'approach', 'steps': [[True, True, True], [False, True, True], [True, True, False], [True, True, False], [False, True, True], [False, False, False], [False, False, False], [True, False, True], [False, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('boundary: automatic signal re-clears', {'mode': 'auto', 'steps': [[False, False, False], [True, False, True], [False, False, False]]}, ['clear', 'danger', 'clear']), ('control 12', {'mode': 'controlled', 'steps': [[False, False, True], [False, True, True], [True, False, True], [False, False, False], [False, False, True], [True, True, True], [True, False, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 15', {'mode': 'approach', 'steps': [[False, True, True], [False, True, False], [False, True, True]]}, ['clear', 'danger', 'clear']), ('control 18', {'mode': 'approach', 'steps': [[False, True, False], [False, False, False], [False, False, False], [True, True, False], [False, True, False], [True, True, True], [False, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear'])], [('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 19', {'mode': 'controlled', 'steps': [[True, False, False], [False, False, True], [True, True, True], [False, False, True], [False, False, True], [False, True, True], [True, True, True], [False, True, False]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'danger', 'danger']), ('sampled regression 64', {'mode': 'approach', 'steps': [[True, True, True], [False, False, True], [False, True, True], [True, True, True], [True, True, False], [False, True, False], [False, True, False], [False, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('boundary: automatic signal re-clears', {'mode': 'auto', 'steps': [[False, False, False], [True, False, True], [False, False, False]]}, ['clear', 'danger', 'clear']), ('sampled regression 23', {'mode': 'controlled', 'steps': [[False, True, True], [False, True, False], [False, True, True], [True, True, False], [False, True, False]]}, ['clear', 'clear', 'clear', 'danger', 'danger']), ('control 26', {'mode': 'approach', 'steps': [[False, False, False], [False, True, True], [True, True, False], [True, False, True], [True, True, False], [True, False, True], [False, False, False], [False, True, True], [False, False, True], [False, True, False]]}, ['danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'danger', 'danger']), ('control 29', {'mode': 'auto', 'steps': [[True, False, False], [False, False, False], [True, False, False], [False, False, True], [False, False, False], [False, True, True], [False, True, True], [False, False, False], [True, False, True], [False, True, False]]}, ['danger', 'clear', 'danger', 'clear', 'clear', 'clear', 'clear', 'clear', 'danger', 'clear'])], [('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('boundary: controlled signal with a standing train', {'mode': 'controlled', 'steps': [[True, True, True], [False, True, True]]}, ['danger', 'clear']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('boundary: approach-released signal with empty approach', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True]]}, ['danger', 'clear']), ('control 34', {'mode': 'approach', 'steps': [[False, True, True], [False, False, False], [False, True, True], [False, False, False], [True, False, True], [False, False, True], [True, False, False], [True, False, True]]}, ['clear', 'danger', 'clear', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 37', {'mode': 'approach', 'steps': [[False, False, True], [True, False, False], [False, False, True], [False, False, True], [True, False, True], [False, False, False], [False, False, True], [False, False, True], [False, False, False]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger']), ('control 40', {'mode': 'auto', 'steps': [[False, True, True], [True, True, True], [False, True, True], [False, True, False], [True, False, True], [True, False, True], [True, False, True]]}, ['clear', 'danger', 'clear', 'clear', 'danger', 'danger', 'danger'])], [('regression: second train behind on the same route', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('regression: approach-released signal replaced by train', {'mode': 'approach', 'steps': [[False, True, True], [True, True, True], [False, True, True]]}, ['clear', 'danger', 'danger']), ('sampled regression 24', {'mode': 'controlled', 'steps': [[False, False, True], [False, False, True], [False, True, False], [False, True, True], [False, True, True], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'danger', 'clear', 'clear', 'clear', 'danger', 'danger', 'danger']), ('sampled regression 5', {'mode': 'approach', 'steps': [[False, True, False], [False, True, True], [False, True, True], [True, True, False], [True, True, True], [False, True, True], [False, True, True]]}, ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger']), ('boundary: route re-set after a train', {'mode': 'controlled', 'steps': [[False, True, True], [True, True, True], [False, False, True], [False, True, True]]}, ['clear', 'danger', 'danger', 'clear']), ('control 45', {'mode': 'approach', 'steps': [[False, False, False], [False, False, False], [False, True, False], [False, True, False], [True, True, False], [False, True, False], [False, True, False], [False, True, True]]}, ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear']), ('control 48', {'mode': 'approach', 'steps': [[True, True, False], [False, True, True], [False, False, False], [False, False, True], [False, True, True], [True, True, False]]}, ['danger', 'clear', 'danger', 'danger', 'clear', 'danger']), ('control 51', {'mode': 'controlled', 'steps': [[False, False, True], [False, False, False], [False, True, False], [False, True, True], [True, False, True], [False, False, True], [True, True, False]]}, ['danger', 'danger', 'clear', 'clear', 'danger', 'danger', 'danger'])]]
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 behind on the same route | ['clear', 'danger', 'danger'] | ['clear', 'danger', 'danger'] | Passed |
| regression: approach-released signal replaced by train | ['clear', 'danger', 'danger'] | ['clear', 'danger', 'danger'] | Passed |
| sampled regression 5 | ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger'] | ['danger', 'clear', 'clear', 'danger', 'danger', 'danger', 'danger'] | Passed |
| boundary: route re-set after a train | ['clear', 'danger', 'danger', 'clear'] | ['clear', 'danger', 'danger', 'clear'] | Passed |
| boundary: approach-released signal with empty approach | ['danger', 'clear'] | ['danger', 'clear'] | Passed |
| control 1 | ['clear', 'clear', 'clear', 'clear', 'clear'] | ['clear', 'clear', 'clear', 'clear', 'clear'] | Passed |
| sampled regression 4 | ['danger', 'clear', 'danger', 'danger', 'danger'] | ['danger', 'clear', 'danger', 'danger', 'danger'] | Passed |
| control 7 | ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'] | ['danger', 'danger', 'danger', 'danger', 'danger', 'danger', 'clear', 'clear', 'clear', 'danger'] | Passed |
SHA-256 / bbb2848444211f87f21b0c6cc7a25d5c90c04d7f55d6cc4826ebf9ab12dfc8b1
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.462547+00:00.
Case digest / 92ec696b1f53db3f1d96c39bf020a4ec384b757fde6b4508cc1a052f6d3fa29b