FAILURE MAP
← Case archive

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.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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