FA-67321 / Railway interlocking logic / Open access
Temporary speed restriction over train length: rear clearance · case 01
The train accelerates when its front leaves the restriction while its rear is still inside.
ROOT CAUSE
Restriction applicability is judged by the front of the train only.
VERIFIED REPAIR
Keep the restriction until the rear of the train has cleared its end.
Unsuccessful approach: An inclusive end keeps the train restricted after its rear has exactly cleared.
Case contract
A restriction [from_m, to_m) applies while any part of the train (rear = front - length) is inside it: from <= front and to > rear. The limit is the minimum of the line speed and applicable restrictions. next_m is the start of the nearest restriction ahead of the front (from > front) within sight_m of the front whose speed is below the current limit, else 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):
front = x['front_m']
rear = front - x['length_m']
limit = x['line_kmh']
for s in x['tsr']:
if s['from_m'] <= front and s['to_m'] > front:
limit = min(limit, s['kmh'])
ahead = [s for s in x['tsr'] if s['from_m'] > front and s['from_m'] - front <= x['sight_m'] and s['kmh'] < limit]
nxt = min(ahead, key=lambda s: s['from_m'])['from_m'] if ahead else None
return {'limit': limit, 'next_m': nxt}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 6', {'front_m': 700, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 600, 'kmh': 20}, {'from_m': 1000, 'to_m': 1600, 'kmh': 80}]}, {'limit': 20, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('sampled regression 1', {'front_m': 1100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 40}, {'from_m': 800, 'to_m': 1100, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('sampled regression 4', {'front_m': 700, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1100, 'kmh': 40}, {'from_m': 1000, 'to_m': 1600, 'kmh': 20}, {'from_m': 800, 'to_m': 900, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 20}]}, {'limit': 20, 'next_m': None}), ('control 7', {'front_m': 1100, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 800, 'kmh': 40}, {'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 60, 'next_m': None})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('sampled regression 38', {'front_m': 700, 'length_m': 400, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 500, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 60}, {'from_m': 1500, 'to_m': 1600, 'kmh': 20}]}, {'limit': 80, 'next_m': None}), ('control 37', {'front_m': 500, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1600, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1800, 'kmh': 20}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('sampled regression 12', {'front_m': 1300, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 500, 'to_m': 1100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1600, 'kmh': 20}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 20, 'next_m': None}), ('control 15', {'front_m': 100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 60}, {'from_m': 800, 'to_m': 900, 'kmh': 20}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 120, 'next_m': 200}), ('control 18', {'front_m': 700, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 120, 'next_m': 1000})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 68', {'front_m': 250, 'length_m': 400, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 500, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 60}, {'from_m': 1500, 'to_m': 2100, 'kmh': 40}, {'from_m': 1500, 'to_m': 1800, 'kmh': 80}]}, {'limit': 60, 'next_m': None}), ('control 72', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 200, 'to_m': 300, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 80}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('boundary: two restrictions ahead listed far first', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 600, 'kmh': 40}, {'from_m': 300, 'to_m': 400, 'kmh': 60}]}, {'limit': 100, 'next_m': 300}), ('control 23', {'front_m': 700, 'length_m': 100, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 200, 'to_m': 300, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 80}]}, {'limit': 120, 'next_m': 800}), ('control 26', {'front_m': 500, 'length_m': 100, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 40}]}, {'limit': 120, 'next_m': 800}), ('control 29', {'front_m': 100, 'length_m': 200, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 300, 'kmh': 20}, {'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 20}]}, {'limit': 20, 'next_m': None})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('sampled regression 27', {'front_m': 1100, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 1600, 'kmh': 60}, {'from_m': 1000, 'to_m': 1100, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 80}, {'from_m': 1500, 'to_m': 1800, 'kmh': 60}]}, {'limit': 20, 'next_m': None}), ('control 8', {'front_m': 500, 'length_m': 200, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 80}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 120, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('control 34', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1300, 'kmh': 80}, {'from_m': 0, 'to_m': 300, 'kmh': 20}, {'from_m': 1000, 'to_m': 1600, 'kmh': 80}, {'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 100, 'next_m': 1000}), ('control 37', {'front_m': 500, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1600, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1800, 'kmh': 20}]}, {'limit': 40, 'next_m': None}), ('control 40', {'front_m': 1300, 'length_m': 200, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1000, 'to_m': 1100, 'kmh': 60}, {'from_m': 1500, 'to_m': 2100, 'kmh': 20}]}, {'limit': 120, 'next_m': 1500})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 50', {'front_m': 1100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 500, 'to_m': 800, 'kmh': 60}, {'from_m': 800, 'to_m': 1100, 'kmh': 60}, {'from_m': 500, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('control 42', {'front_m': 1300, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 20}, {'from_m': 800, 'to_m': 900, 'kmh': 60}, {'from_m': 500, 'to_m': 600, 'kmh': 40}, {'from_m': 200, 'to_m': 300, 'kmh': 80}]}, {'limit': 100, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('control 45', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 300, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 800, 'to_m': 1100, 'kmh': 40}, {'from_m': 200, 'to_m': 500, 'kmh': 60}]}, {'limit': 80, 'next_m': 800}), ('sampled regression 48', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 800, 'to_m': 1400, 'kmh': 80}, {'from_m': 1000, 'to_m': 1100, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}]}, {'limit': 20, 'next_m': None}), ('control 51', {'front_m': 900, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None})]]
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: rear still inside the restriction | {'limit': 100, 'next_m': None} | {'limit': 40, 'next_m': None} | Failed |
| boundary: rear exactly at the restriction end | {'limit': 100, 'next_m': None} | {'limit': 100, 'next_m': None} | Passed |
| sampled regression 6 | {'limit': 100, 'next_m': 1000} | {'limit': 20, 'next_m': None} | Failed |
| boundary: restriction just behind the rear | {'limit': 100, 'next_m': None} | {'limit': 100, 'next_m': None} | Passed |
| boundary: restriction ahead faster than current limit | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| sampled regression 1 | {'limit': 120, 'next_m': None} | {'limit': 40, 'next_m': None} | Failed |
| sampled regression 4 | {'limit': 120, 'next_m': 800} | {'limit': 20, 'next_m': None} | Failed |
| control 7 | {'limit': 60, 'next_m': None} | {'limit': 60, 'next_m': None} | Passed |
SHA-256 / aa4cbaa39935b400290e5f5922a9c83e293642ca497b6cef2552ccdc33446252
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
front = x['front_m']
rear = front - x['length_m']
limit = x['line_kmh']
for s in x['tsr']:
if s['from_m'] <= front and s['to_m'] >= rear:
limit = min(limit, s['kmh'])
ahead = [s for s in x['tsr'] if s['from_m'] > front and s['from_m'] - front <= x['sight_m'] and s['kmh'] < limit]
nxt = min(ahead, key=lambda s: s['from_m'])['from_m'] if ahead else None
return {'limit': limit, 'next_m': nxt}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 6', {'front_m': 700, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 600, 'kmh': 20}, {'from_m': 1000, 'to_m': 1600, 'kmh': 80}]}, {'limit': 20, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('sampled regression 1', {'front_m': 1100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 40}, {'from_m': 800, 'to_m': 1100, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('sampled regression 4', {'front_m': 700, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1100, 'kmh': 40}, {'from_m': 1000, 'to_m': 1600, 'kmh': 20}, {'from_m': 800, 'to_m': 900, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 20}]}, {'limit': 20, 'next_m': None}), ('control 7', {'front_m': 1100, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 800, 'kmh': 40}, {'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 60, 'next_m': None})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('sampled regression 38', {'front_m': 700, 'length_m': 400, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 500, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 60}, {'from_m': 1500, 'to_m': 1600, 'kmh': 20}]}, {'limit': 80, 'next_m': None}), ('control 37', {'front_m': 500, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1600, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1800, 'kmh': 20}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('sampled regression 12', {'front_m': 1300, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 500, 'to_m': 1100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1600, 'kmh': 20}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 20, 'next_m': None}), ('control 15', {'front_m': 100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 60}, {'from_m': 800, 'to_m': 900, 'kmh': 20}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 120, 'next_m': 200}), ('control 18', {'front_m': 700, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 120, 'next_m': 1000})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 68', {'front_m': 250, 'length_m': 400, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 500, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 60}, {'from_m': 1500, 'to_m': 2100, 'kmh': 40}, {'from_m': 1500, 'to_m': 1800, 'kmh': 80}]}, {'limit': 60, 'next_m': None}), ('control 72', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 200, 'to_m': 300, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 80}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('boundary: two restrictions ahead listed far first', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 600, 'kmh': 40}, {'from_m': 300, 'to_m': 400, 'kmh': 60}]}, {'limit': 100, 'next_m': 300}), ('control 23', {'front_m': 700, 'length_m': 100, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 200, 'to_m': 300, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 80}]}, {'limit': 120, 'next_m': 800}), ('control 26', {'front_m': 500, 'length_m': 100, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 40}]}, {'limit': 120, 'next_m': 800}), ('control 29', {'front_m': 100, 'length_m': 200, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 300, 'kmh': 20}, {'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 20}]}, {'limit': 20, 'next_m': None})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('sampled regression 27', {'front_m': 1100, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 1600, 'kmh': 60}, {'from_m': 1000, 'to_m': 1100, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 80}, {'from_m': 1500, 'to_m': 1800, 'kmh': 60}]}, {'limit': 20, 'next_m': None}), ('control 8', {'front_m': 500, 'length_m': 200, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 80}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 120, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('control 34', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1300, 'kmh': 80}, {'from_m': 0, 'to_m': 300, 'kmh': 20}, {'from_m': 1000, 'to_m': 1600, 'kmh': 80}, {'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 100, 'next_m': 1000}), ('control 37', {'front_m': 500, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1600, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1800, 'kmh': 20}]}, {'limit': 40, 'next_m': None}), ('control 40', {'front_m': 1300, 'length_m': 200, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1000, 'to_m': 1100, 'kmh': 60}, {'from_m': 1500, 'to_m': 2100, 'kmh': 20}]}, {'limit': 120, 'next_m': 1500})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 50', {'front_m': 1100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 500, 'to_m': 800, 'kmh': 60}, {'from_m': 800, 'to_m': 1100, 'kmh': 60}, {'from_m': 500, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('control 42', {'front_m': 1300, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 20}, {'from_m': 800, 'to_m': 900, 'kmh': 60}, {'from_m': 500, 'to_m': 600, 'kmh': 40}, {'from_m': 200, 'to_m': 300, 'kmh': 80}]}, {'limit': 100, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('control 45', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 300, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 800, 'to_m': 1100, 'kmh': 40}, {'from_m': 200, 'to_m': 500, 'kmh': 60}]}, {'limit': 80, 'next_m': 800}), ('sampled regression 48', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 800, 'to_m': 1400, 'kmh': 80}, {'from_m': 1000, 'to_m': 1100, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}]}, {'limit': 20, 'next_m': None}), ('control 51', {'front_m': 900, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None})]]
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: rear still inside the restriction | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| boundary: rear exactly at the restriction end | {'limit': 40, 'next_m': None} | {'limit': 100, 'next_m': None} | Failed |
| sampled regression 6 | {'limit': 20, 'next_m': None} | {'limit': 20, 'next_m': None} | Passed |
| boundary: restriction just behind the rear | {'limit': 20, 'next_m': None} | {'limit': 100, 'next_m': None} | Failed |
| boundary: restriction ahead faster than current limit | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| sampled regression 1 | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| sampled regression 4 | {'limit': 20, 'next_m': None} | {'limit': 20, 'next_m': None} | Passed |
| control 7 | {'limit': 60, 'next_m': None} | {'limit': 60, 'next_m': None} | Passed |
SHA-256 / 19b2ff361ccd401240f3b43f2d6ef1e3be1003c07d7005cfac51ccae9359aa0a
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
front = x['front_m']
rear = front - x['length_m']
limit = x['line_kmh']
for s in x['tsr']:
if s['from_m'] <= front and s['to_m'] > rear:
limit = min(limit, s['kmh'])
ahead = [s for s in x['tsr'] if s['from_m'] > front and s['from_m'] - front <= x['sight_m'] and s['kmh'] < limit]
nxt = min(ahead, key=lambda s: s['from_m'])['from_m'] if ahead else None
return {'limit': limit, 'next_m': nxt}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 6', {'front_m': 700, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 600, 'kmh': 20}, {'from_m': 1000, 'to_m': 1600, 'kmh': 80}]}, {'limit': 20, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('sampled regression 1', {'front_m': 1100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 40}, {'from_m': 800, 'to_m': 1100, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('sampled regression 4', {'front_m': 700, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1100, 'kmh': 40}, {'from_m': 1000, 'to_m': 1600, 'kmh': 20}, {'from_m': 800, 'to_m': 900, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 20}]}, {'limit': 20, 'next_m': None}), ('control 7', {'front_m': 1100, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 800, 'kmh': 40}, {'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 60, 'next_m': None})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('sampled regression 38', {'front_m': 700, 'length_m': 400, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 500, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 60}, {'from_m': 1500, 'to_m': 1600, 'kmh': 20}]}, {'limit': 80, 'next_m': None}), ('control 37', {'front_m': 500, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1600, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1800, 'kmh': 20}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('sampled regression 12', {'front_m': 1300, 'length_m': 400, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 500, 'to_m': 1100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1600, 'kmh': 20}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 20, 'next_m': None}), ('control 15', {'front_m': 100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 60}, {'from_m': 800, 'to_m': 900, 'kmh': 20}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 120, 'next_m': 200}), ('control 18', {'front_m': 700, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 120, 'next_m': 1000})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 68', {'front_m': 250, 'length_m': 400, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 500, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 60}, {'from_m': 1500, 'to_m': 2100, 'kmh': 40}, {'from_m': 1500, 'to_m': 1800, 'kmh': 80}]}, {'limit': 60, 'next_m': None}), ('control 72', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 200, 'to_m': 300, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 80}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('boundary: two restrictions ahead listed far first', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 600, 'kmh': 40}, {'from_m': 300, 'to_m': 400, 'kmh': 60}]}, {'limit': 100, 'next_m': 300}), ('control 23', {'front_m': 700, 'length_m': 100, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 200, 'to_m': 300, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 80}]}, {'limit': 120, 'next_m': 800}), ('control 26', {'front_m': 500, 'length_m': 100, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 40}]}, {'limit': 120, 'next_m': 800}), ('control 29', {'front_m': 100, 'length_m': 200, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 300, 'kmh': 20}, {'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 0, 'to_m': 100, 'kmh': 20}]}, {'limit': 20, 'next_m': None})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: restriction just behind the rear', {'front_m': 1000, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 900, 'kmh': 20}]}, {'limit': 100, 'next_m': None}), ('sampled regression 27', {'front_m': 1100, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 1600, 'kmh': 60}, {'from_m': 1000, 'to_m': 1100, 'kmh': 20}, {'from_m': 500, 'to_m': 600, 'kmh': 80}, {'from_m': 1500, 'to_m': 1800, 'kmh': 60}]}, {'limit': 20, 'next_m': None}), ('control 8', {'front_m': 500, 'length_m': 200, 'line_kmh': 120, 'sight_m': 300, 'tsr': [{'from_m': 1500, 'to_m': 2100, 'kmh': 80}, {'from_m': 200, 'to_m': 300, 'kmh': 40}]}, {'limit': 120, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('control 34', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1300, 'kmh': 80}, {'from_m': 0, 'to_m': 300, 'kmh': 20}, {'from_m': 1000, 'to_m': 1600, 'kmh': 80}, {'from_m': 1000, 'to_m': 1300, 'kmh': 60}]}, {'limit': 100, 'next_m': 1000}), ('control 37', {'front_m': 500, 'length_m': 400, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 1000, 'to_m': 1600, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}, {'from_m': 1500, 'to_m': 1800, 'kmh': 20}]}, {'limit': 40, 'next_m': None}), ('control 40', {'front_m': 1300, 'length_m': 200, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 1000, 'to_m': 1100, 'kmh': 60}, {'from_m': 1500, 'to_m': 2100, 'kmh': 20}]}, {'limit': 120, 'next_m': 1500})], [('regression: rear still inside the restriction', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('boundary: rear exactly at the restriction end', {'front_m': 800, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None}), ('sampled regression 50', {'front_m': 1100, 'length_m': 400, 'line_kmh': 120, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 800, 'kmh': 40}, {'from_m': 500, 'to_m': 800, 'kmh': 60}, {'from_m': 800, 'to_m': 1100, 'kmh': 60}, {'from_m': 500, 'to_m': 600, 'kmh': 40}]}, {'limit': 40, 'next_m': None}), ('control 42', {'front_m': 1300, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 20}, {'from_m': 800, 'to_m': 900, 'kmh': 60}, {'from_m': 500, 'to_m': 600, 'kmh': 40}, {'from_m': 200, 'to_m': 300, 'kmh': 80}]}, {'limit': 100, 'next_m': None}), ('boundary: restriction ahead faster than current limit', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 400, 'to_m': 600, 'kmh': 40}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 40, 'next_m': None}), ('control 45', {'front_m': 700, 'length_m': 200, 'line_kmh': 100, 'sight_m': 300, 'tsr': [{'from_m': 0, 'to_m': 300, 'kmh': 60}, {'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 800, 'to_m': 1100, 'kmh': 40}, {'from_m': 200, 'to_m': 500, 'kmh': 60}]}, {'limit': 80, 'next_m': 800}), ('sampled regression 48', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 200, 'to_m': 800, 'kmh': 80}, {'from_m': 800, 'to_m': 1400, 'kmh': 80}, {'from_m': 1000, 'to_m': 1100, 'kmh': 40}, {'from_m': 0, 'to_m': 100, 'kmh': 20}]}, {'limit': 20, 'next_m': None}), ('control 51', {'front_m': 900, 'length_m': 200, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 500, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': None})]]
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: rear still inside the restriction | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| boundary: rear exactly at the restriction end | {'limit': 100, 'next_m': None} | {'limit': 100, 'next_m': None} | Passed |
| sampled regression 6 | {'limit': 20, 'next_m': None} | {'limit': 20, 'next_m': None} | Passed |
| boundary: restriction just behind the rear | {'limit': 100, 'next_m': None} | {'limit': 100, 'next_m': None} | Passed |
| boundary: restriction ahead faster than current limit | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| sampled regression 1 | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| sampled regression 4 | {'limit': 20, 'next_m': None} | {'limit': 20, 'next_m': None} | Passed |
| control 7 | {'limit': 60, 'next_m': None} | {'limit': 60, 'next_m': None} | Passed |
SHA-256 / dd2deedc008cfe96dab55bd301a0b3e89ee7a1c09f6bb4db847f7ef218b25474
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:51.850101+00:00.
Case digest / ac5670e336b2d60606f1fe2af8a731149c0b5126c6bac04bf83b8ee9fbfca1fe