FA-67331 / Railway interlocking logic / Open access
Temporary speed restriction over train length: nearest restriction · case 01
The announced restriction is not the nearest one ahead.
ROOT CAUSE
The slowest restriction is announced instead of the nearest.
VERIFIED REPAIR
Announce the restriction with the smallest start position.
Unsuccessful approach: Taking the first listed restriction depends on table order.
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'] > 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['kmh'])['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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('boundary: 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}), ('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 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}), ('control 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: 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}), ('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}), ('boundary: restriction ahead slower than line speed only', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 450, 'to_m': 700, 'kmh': 30}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 30, 'next_m': None}), ('boundary: restriction exactly at sighting distance', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 600, 'to_m': 700, 'kmh': 40}]}, {'limit': 100, 'next_m': 600}), ('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}), ('control 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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('boundary: restriction exactly at sighting distance', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 600, 'to_m': 700, 'kmh': 40}]}, {'limit': 100, 'next_m': 600}), ('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: 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}), ('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: 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}), ('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: 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}), ('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 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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('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}), ('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}), ('boundary: restriction ahead slower than line speed only', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 450, 'to_m': 700, 'kmh': 30}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 30, '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}), ('control 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: two restrictions ahead listed far first | {'limit': 100, 'next_m': 500} | {'limit': 100, 'next_m': 300} | Failed |
| sampled regression 58 | {'limit': 100, 'next_m': 1000} | {'limit': 100, 'next_m': 800} | Failed |
| boundary: 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 |
| boundary: restriction ahead faster than current limit | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| control 1 | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| control 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 / e1e58e2b63a7803a3f5d5b73c4302b8724bd2930422f15e8e2920ce42ae8f476
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 = ahead[0]['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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('boundary: 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}), ('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 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}), ('control 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: 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}), ('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}), ('boundary: restriction ahead slower than line speed only', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 450, 'to_m': 700, 'kmh': 30}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 30, 'next_m': None}), ('boundary: restriction exactly at sighting distance', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 600, 'to_m': 700, 'kmh': 40}]}, {'limit': 100, 'next_m': 600}), ('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}), ('control 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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('boundary: restriction exactly at sighting distance', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 600, 'to_m': 700, 'kmh': 40}]}, {'limit': 100, 'next_m': 600}), ('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: 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}), ('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: 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}), ('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: 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}), ('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 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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('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}), ('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}), ('boundary: restriction ahead slower than line speed only', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 450, 'to_m': 700, 'kmh': 30}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 30, '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}), ('control 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: two restrictions ahead listed far first | {'limit': 100, 'next_m': 500} | {'limit': 100, 'next_m': 300} | Failed |
| sampled regression 58 | {'limit': 100, 'next_m': 800} | {'limit': 100, 'next_m': 800} | Passed |
| boundary: 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 |
| boundary: restriction ahead faster than current limit | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| control 1 | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| control 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 / 79c6f8d0f6229624726613c19a3621baf43231b2378f20e6c34857856b3f1710
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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('boundary: 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}), ('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 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}), ('control 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: 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}), ('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}), ('boundary: restriction ahead slower than line speed only', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 450, 'to_m': 700, 'kmh': 30}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 30, 'next_m': None}), ('boundary: restriction exactly at sighting distance', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 600, 'to_m': 700, 'kmh': 40}]}, {'limit': 100, 'next_m': 600}), ('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}), ('control 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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('boundary: restriction exactly at sighting distance', {'front_m': 100, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 600, 'to_m': 700, 'kmh': 40}]}, {'limit': 100, 'next_m': 600}), ('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: 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}), ('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: 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}), ('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: 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}), ('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 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: 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}), ('sampled regression 58', {'front_m': 700, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 800, 'to_m': 1100, 'kmh': 80}, {'from_m': 1000, 'to_m': 1600, 'kmh': 40}, {'from_m': 0, 'to_m': 600, 'kmh': 40}]}, {'limit': 100, 'next_m': 800}), ('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}), ('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}), ('boundary: restriction ahead slower than line speed only', {'front_m': 500, 'length_m': 100, 'line_kmh': 100, 'sight_m': 500, 'tsr': [{'from_m': 450, 'to_m': 700, 'kmh': 30}, {'from_m': 800, 'to_m': 900, 'kmh': 60}]}, {'limit': 30, '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}), ('control 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: two restrictions ahead listed far first | {'limit': 100, 'next_m': 300} | {'limit': 100, 'next_m': 300} | Passed |
| sampled regression 58 | {'limit': 100, 'next_m': 800} | {'limit': 100, 'next_m': 800} | Passed |
| boundary: 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 |
| boundary: restriction ahead faster than current limit | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| control 1 | {'limit': 40, 'next_m': None} | {'limit': 40, 'next_m': None} | Passed |
| control 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 / a6d0714739b5bf27f3d4a9fd5f3b0c8d149dffbb112675d4307443430b53a828
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.938195+00:00.
Case digest / 07e1413b2552b4dd61920697da587a6e09385c3f519f63f3e902bc25936902ae