FAILURE MAP
← Case archive

FA-66881 / Railway interlocking logic / Open access

Four-aspect signal chain evaluation: line end boundary · case 01

The last signal before a buffer stop shows green.

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

ROOT CAUSE

The chain is seeded as if the line always continued, ignoring the buffer stop.

VERIFIED REPAIR

Seed the chain with R at a buffer stop and G on an open line.

Unsuccessful approach: Seeding an open line with Y makes the last signal show YY and degrades the whole chain.

Case contract

Signals 0..n-1 each protect one block; occupied[i] is the block after signal i. Evaluate from the far end: a signal shows R if its block is occupied, else Y if the next signal is R, R if the next signal is DARK, YY if the next is Y, otherwise G. Beyond the last signal the next aspect is G on an open line and R at a buffer stop. A diverging signal is capped at Y. A signal whose red lamp has failed shows DARK instead of R.

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):
    occ = x['occupied']
    n = len(occ)
    fail = set(x['lamp_fail'])
    div = set(x['diverging'])
    nxt = 'G'
    out = [None] * n
    for i in range(n - 1, -1, -1):
        if occ[i]:
            a = 'R'
        elif nxt in ('R', 'DARK'):
            a = 'R' if nxt == 'DARK' else 'Y'
        elif nxt == 'Y':
            a = 'YY'
        else:
            a = 'G'
        if i in div and a in ('YY', 'G'):
            a = 'Y'
        if a == 'R' and i in fail:
            a = 'DARK'
        out[i] = a
        nxt = a
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 3', {'occupied': [True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['R', 'G', 'YY', 'Y']), ('boundary: diverging junction behind a green', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 1', {'occupied': [False, True, False, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'G', 'YY', 'Y']), ('control 4', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R']), ('control 7', {'occupied': [True, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': True}, ['R', 'YY', 'Y', 'R'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: diverging junction behind a green', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G']), ('sampled regression 41', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 14', {'occupied': [False, False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'YY', 'Y', 'R', 'G']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('sampled regression 12', {'occupied': [False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 15', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['Y', 'R']), ('control 18', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G'])], [('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: open line', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 67', {'occupied': [False, True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'YY', 'Y']), ('control 28', {'occupied': [False, False, False, True, False, False, False], 'lamp_fail': [6], 'diverging': [1, 5], 'open_end': True}, ['YY', 'Y', 'Y', 'R', 'YY', 'Y', 'G']), ('boundary: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('control 23', {'occupied': [True, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['R', 'Y', 'R']), ('control 26', {'occupied': [False, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': False}, ['G', 'YY', 'Y', 'R']), ('control 29', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('sampled regression 3', {'occupied': [True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['R', 'G', 'YY', 'Y']), ('control 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 34', {'occupied': [False, False, False, False, False, False, False], 'lamp_fail': [], 'diverging': [1], 'open_end': False}, ['YY', 'Y', 'G', 'G', 'G', 'YY', 'Y']), ('control 37', {'occupied': [False, False, False, False], 'lamp_fail': [0], 'diverging': [0, 3], 'open_end': True}, ['Y', 'G', 'YY', 'Y']), ('control 40', {'occupied': [False, False, False, False], 'lamp_fail': [0], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G', 'G'])], [('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 41', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 66', {'occupied': [False, False, False], 'lamp_fail': [2], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('control 45', {'occupied': [True, False, False, True], 'lamp_fail': [3], 'diverging': [1], 'open_end': True}, ['R', 'Y', 'R', 'DARK']), ('control 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('control 51', {'occupied': [False, False, False, True], 'lamp_fail': [], 'diverging': [0, 2, 3], 'open_end': True}, ['Y', 'YY', 'Y', 'R'])]]
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: buffer stop at the end['G', 'G', 'G']['G', 'YY', 'Y']Failed
boundary: failed red lamp on a clear signal['G', 'G', 'G']['G', 'G', 'G']Passed
sampled regression 3['R', 'G', 'G', 'G']['R', 'G', 'YY', 'Y']Failed
boundary: diverging junction behind a green['Y', 'G', 'G']['Y', 'G', 'G']Passed
boundary: dark signal ahead['R', 'DARK']['R', 'DARK']Passed
sampled regression 1['Y', 'R', 'G', 'G', 'G', 'G']['Y', 'R', 'G', 'G', 'YY', 'Y']Failed
control 4['Y', 'R']['Y', 'R']Passed
control 7['R', 'YY', 'Y', 'R']['R', 'YY', 'Y', 'R']Passed

SHA-256 / 1cfb8641c0e7ed7db473e880693d05592e73a5f75d71e142b34dd6f315528d2f

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    occ = x['occupied']
    n = len(occ)
    fail = set(x['lamp_fail'])
    div = set(x['diverging'])
    nxt = 'Y' if x['open_end'] else 'R'
    out = [None] * n
    for i in range(n - 1, -1, -1):
        if occ[i]:
            a = 'R'
        elif nxt in ('R', 'DARK'):
            a = 'R' if nxt == 'DARK' else 'Y'
        elif nxt == 'Y':
            a = 'YY'
        else:
            a = 'G'
        if i in div and a in ('YY', 'G'):
            a = 'Y'
        if a == 'R' and i in fail:
            a = 'DARK'
        out[i] = a
        nxt = a
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 3', {'occupied': [True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['R', 'G', 'YY', 'Y']), ('boundary: diverging junction behind a green', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 1', {'occupied': [False, True, False, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'G', 'YY', 'Y']), ('control 4', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R']), ('control 7', {'occupied': [True, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': True}, ['R', 'YY', 'Y', 'R'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: diverging junction behind a green', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G']), ('sampled regression 41', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 14', {'occupied': [False, False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'YY', 'Y', 'R', 'G']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('sampled regression 12', {'occupied': [False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 15', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['Y', 'R']), ('control 18', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G'])], [('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: open line', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 67', {'occupied': [False, True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'YY', 'Y']), ('control 28', {'occupied': [False, False, False, True, False, False, False], 'lamp_fail': [6], 'diverging': [1, 5], 'open_end': True}, ['YY', 'Y', 'Y', 'R', 'YY', 'Y', 'G']), ('boundary: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('control 23', {'occupied': [True, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['R', 'Y', 'R']), ('control 26', {'occupied': [False, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': False}, ['G', 'YY', 'Y', 'R']), ('control 29', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('sampled regression 3', {'occupied': [True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['R', 'G', 'YY', 'Y']), ('control 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 34', {'occupied': [False, False, False, False, False, False, False], 'lamp_fail': [], 'diverging': [1], 'open_end': False}, ['YY', 'Y', 'G', 'G', 'G', 'YY', 'Y']), ('control 37', {'occupied': [False, False, False, False], 'lamp_fail': [0], 'diverging': [0, 3], 'open_end': True}, ['Y', 'G', 'YY', 'Y']), ('control 40', {'occupied': [False, False, False, False], 'lamp_fail': [0], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G', 'G'])], [('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 41', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 66', {'occupied': [False, False, False], 'lamp_fail': [2], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('control 45', {'occupied': [True, False, False, True], 'lamp_fail': [3], 'diverging': [1], 'open_end': True}, ['R', 'Y', 'R', 'DARK']), ('control 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('control 51', {'occupied': [False, False, False, True], 'lamp_fail': [], 'diverging': [0, 2, 3], 'open_end': True}, ['Y', 'YY', 'Y', 'R'])]]
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: buffer stop at the end['G', 'YY', 'Y']['G', 'YY', 'Y']Passed
boundary: failed red lamp on a clear signal['G', 'G', 'YY']['G', 'G', 'G']Failed
sampled regression 3['R', 'G', 'YY', 'Y']['R', 'G', 'YY', 'Y']Passed
boundary: diverging junction behind a green['Y', 'G', 'YY']['Y', 'G', 'G']Failed
boundary: dark signal ahead['R', 'DARK']['R', 'DARK']Passed
sampled regression 1['Y', 'R', 'G', 'G', 'YY', 'Y']['Y', 'R', 'G', 'G', 'YY', 'Y']Passed
control 4['Y', 'R']['Y', 'R']Passed
control 7['R', 'YY', 'Y', 'R']['R', 'YY', 'Y', 'R']Passed

SHA-256 / 4df3a9f8c7298fd7ca451c395288defcfaadb86fb9a551b4c9a8f531281eda8c

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    occ = x['occupied']
    n = len(occ)
    fail = set(x['lamp_fail'])
    div = set(x['diverging'])
    nxt = 'G' if x['open_end'] else 'R'
    out = [None] * n
    for i in range(n - 1, -1, -1):
        if occ[i]:
            a = 'R'
        elif nxt in ('R', 'DARK'):
            a = 'R' if nxt == 'DARK' else 'Y'
        elif nxt == 'Y':
            a = 'YY'
        else:
            a = 'G'
        if i in div and a in ('YY', 'G'):
            a = 'Y'
        if a == 'R' and i in fail:
            a = 'DARK'
        out[i] = a
        nxt = a
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 3', {'occupied': [True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['R', 'G', 'YY', 'Y']), ('boundary: diverging junction behind a green', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 1', {'occupied': [False, True, False, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'G', 'YY', 'Y']), ('control 4', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R']), ('control 7', {'occupied': [True, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': True}, ['R', 'YY', 'Y', 'R'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: diverging junction behind a green', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G']), ('sampled regression 41', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 14', {'occupied': [False, False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'YY', 'Y', 'R', 'G']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('sampled regression 12', {'occupied': [False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 15', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['Y', 'R']), ('control 18', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G'])], [('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: open line', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 67', {'occupied': [False, True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'YY', 'Y']), ('control 28', {'occupied': [False, False, False, True, False, False, False], 'lamp_fail': [6], 'diverging': [1, 5], 'open_end': True}, ['YY', 'Y', 'Y', 'R', 'YY', 'Y', 'G']), ('boundary: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('control 23', {'occupied': [True, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['R', 'Y', 'R']), ('control 26', {'occupied': [False, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': False}, ['G', 'YY', 'Y', 'R']), ('control 29', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('sampled regression 3', {'occupied': [True, False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['R', 'G', 'YY', 'Y']), ('control 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 34', {'occupied': [False, False, False, False, False, False, False], 'lamp_fail': [], 'diverging': [1], 'open_end': False}, ['YY', 'Y', 'G', 'G', 'G', 'YY', 'Y']), ('control 37', {'occupied': [False, False, False, False], 'lamp_fail': [0], 'diverging': [0, 3], 'open_end': True}, ['Y', 'G', 'YY', 'Y']), ('control 40', {'occupied': [False, False, False, False], 'lamp_fail': [0], 'diverging': [0], 'open_end': True}, ['Y', 'G', 'G', 'G'])], [('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('sampled regression 41', {'occupied': [False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('control 66', {'occupied': [False, False, False], 'lamp_fail': [2], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('control 45', {'occupied': [True, False, False, True], 'lamp_fail': [3], 'diverging': [1], 'open_end': True}, ['R', 'Y', 'R', 'DARK']), ('control 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('control 51', {'occupied': [False, False, False, True], 'lamp_fail': [], 'diverging': [0, 2, 3], 'open_end': True}, ['Y', 'YY', 'Y', 'R'])]]
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: buffer stop at the end['G', 'YY', 'Y']['G', 'YY', 'Y']Passed
boundary: failed red lamp on a clear signal['G', 'G', 'G']['G', 'G', 'G']Passed
sampled regression 3['R', 'G', 'YY', 'Y']['R', 'G', 'YY', 'Y']Passed
boundary: diverging junction behind a green['Y', 'G', 'G']['Y', 'G', 'G']Passed
boundary: dark signal ahead['R', 'DARK']['R', 'DARK']Passed
sampled regression 1['Y', 'R', 'G', 'G', 'YY', 'Y']['Y', 'R', 'G', 'G', 'YY', 'Y']Passed
control 4['Y', 'R']['Y', 'R']Passed
control 7['R', 'YY', 'Y', 'R']['R', 'YY', 'Y', 'R']Passed

SHA-256 / 2f576559f5db04fa2a8b6eab2135f5af5f709984cf64b324a7ea4e5463a15127

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

Case digest / 78b0e4f82586f690dd60502f0ac435b3d6d05055668bbbc7eaf621ea334c5757