FAILURE MAP
← Case archive

FA-67251 / Railway interlocking logic / Open access

Sequential point throwing under a power budget: throw time lookup · case 01

Route setting time ignores the individual throw time of slow or fast points.

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

ROOT CAUSE

Every point is assumed to take the default throw time.

VERIFIED REPAIR

Use the per-point throw time, falling back to the default.

Unsuccessful approach: Defaulting to zero makes points without a specific time move instantaneously.

Case contract

A route needs points in given lies (processed in list order). Points already detected in the needed lie are skipped; an undetected point (missing from current) must be thrown. A point that must move but is locked by another route blocks the whole request (blocked:<p>, nothing thrown). At most max_parallel points move at once: each point starts on the earliest-free supply slot (lowest index on ties) and takes its own throw time or the default. Return the start time per thrown point and the time all have finished.

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):
    cur = x['current']
    locked = set(x['locked'])
    todo = []
    for p, pos in x['need']:
        if cur.get(p) == pos:
            continue
        if p in locked:
            return {'result': 'blocked:' + p, 'starts': {}, 'done_s': 0}
        todo.append(p)
    slots = [0] * x['max_parallel']
    starts = {}
    for p in todo:
        k = min(range(len(slots)), key=lambda i: (slots[i], i))
        starts[p] = slots[k]
        slots[k] += x['default_throw_s']
    done = max(slots) if todo else 0
    return {'result': 'set', 'starts': starts, 'done_s': done}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('boundary: locked point already in the right lie', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0}, 'done_s': 5}), ('sampled regression 1', {'need': [['P3', 'R'], ['P6', 'N'], ['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0, 'P6': 0, 'P1': 5}, 'done_s': 11}), ('boundary: undetected point', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P2': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0}, 'done_s': 5}), ('boundary: locked point needing to move', {'need': [['P1', 'R'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'blocked:P1', 'starts': {}, 'done_s': 0}), ('control 4', {'need': [['P1', 'N'], ['P5', 'N']], 'current': {'P1': 'N', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P3': 4, 'P5': 3, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 7', {'need': [['P6', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P4': 'R', 'P5': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('sampled regression 10', {'need': [['P3', 'R'], ['P4', 'N']], 'current': {'P2': 'N', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': ['P1', 'P5'], 'max_parallel': 3, 'throw_s': {'P2': 3, 'P4': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0}, 'done_s': 4})], [('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('boundary: undetected point', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P2': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0}, 'done_s': 5}), ('sampled regression 17', {'need': [['P2', 'N'], ['P5', 'N'], ['P4', 'N']], 'current': {'P1': 'R', 'P3': 'R', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P1': 3, 'P3': 3, 'P5': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0, 'P5': 5}, 'done_s': 11}), ('control 2', {'need': [['P4', 'R'], ['P6', 'R'], ['P5', 'R'], ['P2', 'N']], 'current': {'P1': 'N', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P1'], 'max_parallel': 3, 'throw_s': {'P1': 6, 'P3': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P6': 0, 'P5': 0, 'P2': 0}, 'done_s': 5}), ('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('control 12', {'need': [['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P6'], 'max_parallel': 2, 'throw_s': {'P2': 6, 'P4': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0}, 'done_s': 5}), ('control 15', {'need': [['P1', 'N'], ['P5', 'R'], ['P4', 'R'], ['P3', 'R'], ['P2', 'R']], 'current': {'P2': 'R', 'P4': 'R', 'P5': 'R', 'P6': 'N'}, 'locked': ['P1', 'P4'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P5': 4}, 'default_throw_s': 5}, {'result': 'blocked:P1', 'starts': {}, 'done_s': 0}), ('sampled regression 18', {'need': [['P2', 'N'], ['P3', 'R']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'N', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 6, 'P4': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0, 'P3': 0}, 'done_s': 6})], [('regression: points with individual throw times', {'need': [['P4', 'R'], ['P5', 'N']], 'current': {'P4': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P5': 3}, 'done_s': 8}), ('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('sampled regression 29', {'need': [['P4', 'N'], ['P2', 'N'], ['P1', 'N'], ['P5', 'N'], ['P6', 'R']], 'current': {'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P1': 4, 'P2': 3, 'P3': 6, 'P4': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P1': 6}, 'done_s': 10}), ('control 13', {'need': [['P5', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P1': 3, 'P2': 3, 'P3': 6, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P5': 0, 'P2': 0}, 'done_s': 5}), ('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('sampled regression 23', {'need': [['P3', 'N'], ['P4', 'N'], ['P1', 'R'], ['P6', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P4': 3, 'P5': 4, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P6': 3}, 'done_s': 6}), ('control 26', {'need': [['P1', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P5', 'P6'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 32', {'need': [['P2', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': ['P5', 'P6'], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6, 'P3': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})], [('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('boundary: single supply', {'need': [['P1', 'R'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': [], 'max_parallel': 1, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 5}, 'done_s': 10}), ('sampled regression 49', {'need': [['P5', 'R'], ['P3', 'N'], ['P1', 'N'], ['P4', 'R'], ['P2', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'R', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 3, 'P5': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0, 'P1': 0, 'P4': 3, 'P2': 5}, 'done_s': 10}), ('sampled regression 27', {'need': [['P4', 'R'], ['P2', 'R'], ['P6', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'N'}, 'locked': ['P3'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 4, 'P4': 3, 'P5': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P2': 3, 'P6': 6}, 'done_s': 11}), ('boundary: nothing to move', {'need': [['P1', 'N']], 'current': {'P1': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 34', {'need': [['P3', 'R']], 'current': {'P1': 'R', 'P3': 'N', 'P4': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P1': 6, 'P2': 3, 'P4': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0}, 'done_s': 5}), ('control 37', {'need': [['P5', 'R'], ['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 6, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0}, 'done_s': 5}), ('control 40', {'need': [['P5', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': ['P3'], 'max_parallel': 2, 'throw_s': {'P1': 4, 'P2': 6, 'P3': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})], [('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('regression: points with individual throw times', {'need': [['P4', 'R'], ['P5', 'N']], 'current': {'P4': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P5': 3}, 'done_s': 8}), ('sampled regression 65', {'need': [['P6', 'N']], 'current': {'P3': 'N', 'P4': 'N', 'P5': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P2': 6, 'P3': 4, 'P4': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P6': 0}, 'done_s': 3}), ('control 39', {'need': [['P4', 'N'], ['P3', 'R']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'R', 'P6': 'R'}, 'locked': ['P2'], 'max_parallel': 2, 'throw_s': {'P2': 6, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0}, 'done_s': 5}), ('boundary: locked point already in the right lie', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0}, 'done_s': 5}), ('control 45', {'need': [['P5', 'N'], ['P3', 'R'], ['P2', 'R'], ['P6', 'N'], ['P4', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P1', 'P2', 'P5'], 'max_parallel': 1, 'throw_s': {'P1': 6, 'P2': 4, 'P4': 6, 'P5': 3}, 'default_throw_s': 5}, {'result': 'blocked:P2', 'starts': {}, 'done_s': 0}), ('control 48', {'need': [['P3', 'R']], 'current': {'P1': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P4'], 'max_parallel': 1, 'throw_s': {'P4': 6, 'P5': 6, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0}, 'done_s': 5}), ('control 51', {'need': [['P6', 'R'], ['P5', 'N'], ['P1', 'R'], ['P4', 'N']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': ['P3'], 'max_parallel': 3, 'throw_s': {'P2': 6, 'P3': 6, 'P4': 6, 'P5': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})]]
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: three points on two supplies{'done_s': 10, 'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 5}}{'done_s': 8, 'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}}Failed
boundary: locked point already in the right lie{'done_s': 5, 'result': 'set', 'starts': {'P2': 0}}{'done_s': 5, 'result': 'set', 'starts': {'P2': 0}}Passed
sampled regression 1{'done_s': 10, 'result': 'set', 'starts': {'P1': 5, 'P3': 0, 'P6': 0}}{'done_s': 11, 'result': 'set', 'starts': {'P1': 5, 'P3': 0, 'P6': 0}}Failed
boundary: undetected point{'done_s': 5, 'result': 'set', 'starts': {'P1': 0, 'P2': 0}}{'done_s': 5, 'result': 'set', 'starts': {'P1': 0, 'P2': 0}}Passed
boundary: locked point needing to move{'done_s': 0, 'result': 'blocked:P1', 'starts': {}}{'done_s': 0, 'result': 'blocked:P1', 'starts': {}}Passed
control 4{'done_s': 0, 'result': 'set', 'starts': {}}{'done_s': 0, 'result': 'set', 'starts': {}}Passed
control 7{'done_s': 0, 'result': 'set', 'starts': {}}{'done_s': 0, 'result': 'set', 'starts': {}}Passed
sampled regression 10{'done_s': 5, 'result': 'set', 'starts': {'P4': 0}}{'done_s': 4, 'result': 'set', 'starts': {'P4': 0}}Failed

SHA-256 / 7631529585f3e052b57d4d2e342536bf5cdb781a37a4cbe2f5d54e422e54f14a

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    cur = x['current']
    locked = set(x['locked'])
    todo = []
    for p, pos in x['need']:
        if cur.get(p) == pos:
            continue
        if p in locked:
            return {'result': 'blocked:' + p, 'starts': {}, 'done_s': 0}
        todo.append(p)
    slots = [0] * x['max_parallel']
    starts = {}
    for p in todo:
        k = min(range(len(slots)), key=lambda i: (slots[i], i))
        starts[p] = slots[k]
        slots[k] += x['throw_s'].get(p, 0)
    done = max(slots) if todo else 0
    return {'result': 'set', 'starts': starts, 'done_s': done}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('boundary: locked point already in the right lie', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0}, 'done_s': 5}), ('sampled regression 1', {'need': [['P3', 'R'], ['P6', 'N'], ['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0, 'P6': 0, 'P1': 5}, 'done_s': 11}), ('boundary: undetected point', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P2': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0}, 'done_s': 5}), ('boundary: locked point needing to move', {'need': [['P1', 'R'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'blocked:P1', 'starts': {}, 'done_s': 0}), ('control 4', {'need': [['P1', 'N'], ['P5', 'N']], 'current': {'P1': 'N', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P3': 4, 'P5': 3, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 7', {'need': [['P6', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P4': 'R', 'P5': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('sampled regression 10', {'need': [['P3', 'R'], ['P4', 'N']], 'current': {'P2': 'N', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': ['P1', 'P5'], 'max_parallel': 3, 'throw_s': {'P2': 3, 'P4': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0}, 'done_s': 4})], [('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('boundary: undetected point', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P2': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0}, 'done_s': 5}), ('sampled regression 17', {'need': [['P2', 'N'], ['P5', 'N'], ['P4', 'N']], 'current': {'P1': 'R', 'P3': 'R', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P1': 3, 'P3': 3, 'P5': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0, 'P5': 5}, 'done_s': 11}), ('control 2', {'need': [['P4', 'R'], ['P6', 'R'], ['P5', 'R'], ['P2', 'N']], 'current': {'P1': 'N', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P1'], 'max_parallel': 3, 'throw_s': {'P1': 6, 'P3': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P6': 0, 'P5': 0, 'P2': 0}, 'done_s': 5}), ('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('control 12', {'need': [['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P6'], 'max_parallel': 2, 'throw_s': {'P2': 6, 'P4': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0}, 'done_s': 5}), ('control 15', {'need': [['P1', 'N'], ['P5', 'R'], ['P4', 'R'], ['P3', 'R'], ['P2', 'R']], 'current': {'P2': 'R', 'P4': 'R', 'P5': 'R', 'P6': 'N'}, 'locked': ['P1', 'P4'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P5': 4}, 'default_throw_s': 5}, {'result': 'blocked:P1', 'starts': {}, 'done_s': 0}), ('sampled regression 18', {'need': [['P2', 'N'], ['P3', 'R']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'N', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 6, 'P4': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0, 'P3': 0}, 'done_s': 6})], [('regression: points with individual throw times', {'need': [['P4', 'R'], ['P5', 'N']], 'current': {'P4': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P5': 3}, 'done_s': 8}), ('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('sampled regression 29', {'need': [['P4', 'N'], ['P2', 'N'], ['P1', 'N'], ['P5', 'N'], ['P6', 'R']], 'current': {'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P1': 4, 'P2': 3, 'P3': 6, 'P4': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P1': 6}, 'done_s': 10}), ('control 13', {'need': [['P5', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P1': 3, 'P2': 3, 'P3': 6, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P5': 0, 'P2': 0}, 'done_s': 5}), ('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('sampled regression 23', {'need': [['P3', 'N'], ['P4', 'N'], ['P1', 'R'], ['P6', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P4': 3, 'P5': 4, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P6': 3}, 'done_s': 6}), ('control 26', {'need': [['P1', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P5', 'P6'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 32', {'need': [['P2', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': ['P5', 'P6'], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6, 'P3': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})], [('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('boundary: single supply', {'need': [['P1', 'R'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': [], 'max_parallel': 1, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 5}, 'done_s': 10}), ('sampled regression 49', {'need': [['P5', 'R'], ['P3', 'N'], ['P1', 'N'], ['P4', 'R'], ['P2', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'R', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 3, 'P5': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0, 'P1': 0, 'P4': 3, 'P2': 5}, 'done_s': 10}), ('sampled regression 27', {'need': [['P4', 'R'], ['P2', 'R'], ['P6', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'N'}, 'locked': ['P3'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 4, 'P4': 3, 'P5': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P2': 3, 'P6': 6}, 'done_s': 11}), ('boundary: nothing to move', {'need': [['P1', 'N']], 'current': {'P1': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 34', {'need': [['P3', 'R']], 'current': {'P1': 'R', 'P3': 'N', 'P4': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P1': 6, 'P2': 3, 'P4': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0}, 'done_s': 5}), ('control 37', {'need': [['P5', 'R'], ['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 6, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0}, 'done_s': 5}), ('control 40', {'need': [['P5', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': ['P3'], 'max_parallel': 2, 'throw_s': {'P1': 4, 'P2': 6, 'P3': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})], [('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('regression: points with individual throw times', {'need': [['P4', 'R'], ['P5', 'N']], 'current': {'P4': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P5': 3}, 'done_s': 8}), ('sampled regression 65', {'need': [['P6', 'N']], 'current': {'P3': 'N', 'P4': 'N', 'P5': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P2': 6, 'P3': 4, 'P4': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P6': 0}, 'done_s': 3}), ('control 39', {'need': [['P4', 'N'], ['P3', 'R']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'R', 'P6': 'R'}, 'locked': ['P2'], 'max_parallel': 2, 'throw_s': {'P2': 6, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0}, 'done_s': 5}), ('boundary: locked point already in the right lie', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0}, 'done_s': 5}), ('control 45', {'need': [['P5', 'N'], ['P3', 'R'], ['P2', 'R'], ['P6', 'N'], ['P4', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P1', 'P2', 'P5'], 'max_parallel': 1, 'throw_s': {'P1': 6, 'P2': 4, 'P4': 6, 'P5': 3}, 'default_throw_s': 5}, {'result': 'blocked:P2', 'starts': {}, 'done_s': 0}), ('control 48', {'need': [['P3', 'R']], 'current': {'P1': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P4'], 'max_parallel': 1, 'throw_s': {'P4': 6, 'P5': 6, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0}, 'done_s': 5}), ('control 51', {'need': [['P6', 'R'], ['P5', 'N'], ['P1', 'R'], ['P4', 'N']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': ['P3'], 'max_parallel': 3, 'throw_s': {'P2': 6, 'P3': 6, 'P4': 6, 'P5': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})]]
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: three points on two supplies{'done_s': 6, 'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}}{'done_s': 8, 'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}}Failed
boundary: locked point already in the right lie{'done_s': 0, 'result': 'set', 'starts': {'P2': 0}}{'done_s': 5, 'result': 'set', 'starts': {'P2': 0}}Failed
sampled regression 1{'done_s': 6, 'result': 'set', 'starts': {'P1': 0, 'P3': 0, 'P6': 0}}{'done_s': 11, 'result': 'set', 'starts': {'P1': 5, 'P3': 0, 'P6': 0}}Failed
boundary: undetected point{'done_s': 0, 'result': 'set', 'starts': {'P1': 0, 'P2': 0}}{'done_s': 5, 'result': 'set', 'starts': {'P1': 0, 'P2': 0}}Failed
boundary: locked point needing to move{'done_s': 0, 'result': 'blocked:P1', 'starts': {}}{'done_s': 0, 'result': 'blocked:P1', 'starts': {}}Passed
control 4{'done_s': 0, 'result': 'set', 'starts': {}}{'done_s': 0, 'result': 'set', 'starts': {}}Passed
control 7{'done_s': 0, 'result': 'set', 'starts': {}}{'done_s': 0, 'result': 'set', 'starts': {}}Passed
sampled regression 10{'done_s': 4, 'result': 'set', 'starts': {'P4': 0}}{'done_s': 4, 'result': 'set', 'starts': {'P4': 0}}Passed

SHA-256 / 2fa9ac027e999ab737ec83bdbe69ea54eb13d3978fdb45e0c20817beb953894d

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    cur = x['current']
    locked = set(x['locked'])
    todo = []
    for p, pos in x['need']:
        if cur.get(p) == pos:
            continue
        if p in locked:
            return {'result': 'blocked:' + p, 'starts': {}, 'done_s': 0}
        todo.append(p)
    slots = [0] * x['max_parallel']
    starts = {}
    for p in todo:
        k = min(range(len(slots)), key=lambda i: (slots[i], i))
        starts[p] = slots[k]
        slots[k] += x['throw_s'][p] if p in x['throw_s'] else x['default_throw_s']
    done = max(slots) if todo else 0
    return {'result': 'set', 'starts': starts, 'done_s': done}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('boundary: locked point already in the right lie', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0}, 'done_s': 5}), ('sampled regression 1', {'need': [['P3', 'R'], ['P6', 'N'], ['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0, 'P6': 0, 'P1': 5}, 'done_s': 11}), ('boundary: undetected point', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P2': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0}, 'done_s': 5}), ('boundary: locked point needing to move', {'need': [['P1', 'R'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'blocked:P1', 'starts': {}, 'done_s': 0}), ('control 4', {'need': [['P1', 'N'], ['P5', 'N']], 'current': {'P1': 'N', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P3': 4, 'P5': 3, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 7', {'need': [['P6', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P4': 'R', 'P5': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('sampled regression 10', {'need': [['P3', 'R'], ['P4', 'N']], 'current': {'P2': 'N', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': ['P1', 'P5'], 'max_parallel': 3, 'throw_s': {'P2': 3, 'P4': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0}, 'done_s': 4})], [('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('boundary: undetected point', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P2': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0}, 'done_s': 5}), ('sampled regression 17', {'need': [['P2', 'N'], ['P5', 'N'], ['P4', 'N']], 'current': {'P1': 'R', 'P3': 'R', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P1': 3, 'P3': 3, 'P5': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0, 'P5': 5}, 'done_s': 11}), ('control 2', {'need': [['P4', 'R'], ['P6', 'R'], ['P5', 'R'], ['P2', 'N']], 'current': {'P1': 'N', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P1'], 'max_parallel': 3, 'throw_s': {'P1': 6, 'P3': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P6': 0, 'P5': 0, 'P2': 0}, 'done_s': 5}), ('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('control 12', {'need': [['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P6'], 'max_parallel': 2, 'throw_s': {'P2': 6, 'P4': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0}, 'done_s': 5}), ('control 15', {'need': [['P1', 'N'], ['P5', 'R'], ['P4', 'R'], ['P3', 'R'], ['P2', 'R']], 'current': {'P2': 'R', 'P4': 'R', 'P5': 'R', 'P6': 'N'}, 'locked': ['P1', 'P4'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P5': 4}, 'default_throw_s': 5}, {'result': 'blocked:P1', 'starts': {}, 'done_s': 0}), ('sampled regression 18', {'need': [['P2', 'N'], ['P3', 'R']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'N', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 6, 'P4': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0, 'P3': 0}, 'done_s': 6})], [('regression: points with individual throw times', {'need': [['P4', 'R'], ['P5', 'N']], 'current': {'P4': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P5': 3}, 'done_s': 8}), ('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('sampled regression 29', {'need': [['P4', 'N'], ['P2', 'N'], ['P1', 'N'], ['P5', 'N'], ['P6', 'R']], 'current': {'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P1': 4, 'P2': 3, 'P3': 6, 'P4': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P1': 6}, 'done_s': 10}), ('control 13', {'need': [['P5', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P1': 3, 'P2': 3, 'P3': 6, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P5': 0, 'P2': 0}, 'done_s': 5}), ('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('sampled regression 23', {'need': [['P3', 'N'], ['P4', 'N'], ['P1', 'R'], ['P6', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P4': 3, 'P5': 4, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P6': 3}, 'done_s': 6}), ('control 26', {'need': [['P1', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P5', 'P6'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 32', {'need': [['P2', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': ['P5', 'P6'], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6, 'P3': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})], [('regression: three points on two supplies', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 3, 'P2': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}, 'done_s': 8}), ('boundary: single supply', {'need': [['P1', 'R'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': [], 'max_parallel': 1, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 5}, 'done_s': 10}), ('sampled regression 49', {'need': [['P5', 'R'], ['P3', 'N'], ['P1', 'N'], ['P4', 'R'], ['P2', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'R', 'P4': 'N', 'P5': 'R', 'P6': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 3, 'P5': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0, 'P1': 0, 'P4': 3, 'P2': 5}, 'done_s': 10}), ('sampled regression 27', {'need': [['P4', 'R'], ['P2', 'R'], ['P6', 'R']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'N'}, 'locked': ['P3'], 'max_parallel': 1, 'throw_s': {'P2': 3, 'P3': 4, 'P4': 3, 'P5': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P2': 3, 'P6': 6}, 'done_s': 11}), ('boundary: nothing to move', {'need': [['P1', 'N']], 'current': {'P1': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0}), ('control 34', {'need': [['P3', 'R']], 'current': {'P1': 'R', 'P3': 'N', 'P4': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P1': 6, 'P2': 3, 'P4': 4, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0}, 'done_s': 5}), ('control 37', {'need': [['P5', 'R'], ['P1', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P3': 6, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0}, 'done_s': 5}), ('control 40', {'need': [['P5', 'N']], 'current': {'P1': 'R', 'P2': 'N', 'P3': 'R', 'P4': 'R', 'P5': 'N', 'P6': 'R'}, 'locked': ['P3'], 'max_parallel': 2, 'throw_s': {'P1': 4, 'P2': 6, 'P3': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})], [('regression: long first throw then short ones', {'need': [['P1', 'R'], ['P2', 'R'], ['P3', 'R'], ['P4', 'R']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'N'}, 'locked': [], 'max_parallel': 2, 'throw_s': {'P1': 6, 'P2': 3, 'P3': 3, 'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3, 'P4': 6}, 'done_s': 9}), ('regression: points with individual throw times', {'need': [['P4', 'R'], ['P5', 'N']], 'current': {'P4': 'N', 'P5': 'R'}, 'locked': [], 'max_parallel': 1, 'throw_s': {'P4': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0, 'P5': 3}, 'done_s': 8}), ('sampled regression 65', {'need': [['P6', 'N']], 'current': {'P3': 'N', 'P4': 'N', 'P5': 'R', 'P6': 'R'}, 'locked': [], 'max_parallel': 3, 'throw_s': {'P2': 6, 'P3': 4, 'P4': 3, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P6': 0}, 'done_s': 3}), ('control 39', {'need': [['P4', 'N'], ['P3', 'R']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'R', 'P4': 'R', 'P5': 'R', 'P6': 'R'}, 'locked': ['P2'], 'max_parallel': 2, 'throw_s': {'P2': 6, 'P6': 4}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P4': 0}, 'done_s': 5}), ('boundary: locked point already in the right lie', {'need': [['P1', 'N'], ['P2', 'R']], 'current': {'P1': 'N', 'P2': 'N'}, 'locked': ['P1'], 'max_parallel': 2, 'throw_s': {}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P2': 0}, 'done_s': 5}), ('control 45', {'need': [['P5', 'N'], ['P3', 'R'], ['P2', 'R'], ['P6', 'N'], ['P4', 'N']], 'current': {'P1': 'N', 'P2': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P1', 'P2', 'P5'], 'max_parallel': 1, 'throw_s': {'P1': 6, 'P2': 4, 'P4': 6, 'P5': 3}, 'default_throw_s': 5}, {'result': 'blocked:P2', 'starts': {}, 'done_s': 0}), ('control 48', {'need': [['P3', 'R']], 'current': {'P1': 'N', 'P3': 'N', 'P4': 'R', 'P5': 'N', 'P6': 'N'}, 'locked': ['P4'], 'max_parallel': 1, 'throw_s': {'P4': 6, 'P5': 6, 'P6': 3}, 'default_throw_s': 5}, {'result': 'set', 'starts': {'P3': 0}, 'done_s': 5}), ('control 51', {'need': [['P6', 'R'], ['P5', 'N'], ['P1', 'R'], ['P4', 'N']], 'current': {'P1': 'R', 'P2': 'R', 'P3': 'N', 'P4': 'N', 'P5': 'N', 'P6': 'R'}, 'locked': ['P3'], 'max_parallel': 3, 'throw_s': {'P2': 6, 'P3': 6, 'P4': 6, 'P5': 6}, 'default_throw_s': 5}, {'result': 'set', 'starts': {}, 'done_s': 0})]]
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: three points on two supplies{'done_s': 8, 'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}}{'done_s': 8, 'result': 'set', 'starts': {'P1': 0, 'P2': 0, 'P3': 3}}Passed
boundary: locked point already in the right lie{'done_s': 5, 'result': 'set', 'starts': {'P2': 0}}{'done_s': 5, 'result': 'set', 'starts': {'P2': 0}}Passed
sampled regression 1{'done_s': 11, 'result': 'set', 'starts': {'P1': 5, 'P3': 0, 'P6': 0}}{'done_s': 11, 'result': 'set', 'starts': {'P1': 5, 'P3': 0, 'P6': 0}}Passed
boundary: undetected point{'done_s': 5, 'result': 'set', 'starts': {'P1': 0, 'P2': 0}}{'done_s': 5, 'result': 'set', 'starts': {'P1': 0, 'P2': 0}}Passed
boundary: locked point needing to move{'done_s': 0, 'result': 'blocked:P1', 'starts': {}}{'done_s': 0, 'result': 'blocked:P1', 'starts': {}}Passed
control 4{'done_s': 0, 'result': 'set', 'starts': {}}{'done_s': 0, 'result': 'set', 'starts': {}}Passed
control 7{'done_s': 0, 'result': 'set', 'starts': {}}{'done_s': 0, 'result': 'set', 'starts': {}}Passed
sampled regression 10{'done_s': 4, 'result': 'set', 'starts': {'P4': 0}}{'done_s': 4, 'result': 'set', 'starts': {'P4': 0}}Passed

SHA-256 / 8e9ba0a611224e80b770122c575107824d28bc572b701e697b783d2a2d10893e

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.180517+00:00.

Case digest / 1dc2ef0370d41bdb2c9dd749b16ef5926eee9a5240ef416def81775925125ba6