FA-66886 / Railway interlocking logic / Open access
Four-aspect signal chain evaluation: preliminary caution step · case 01
A signal two blocks behind a red shows green instead of double yellow.
ROOT CAUSE
The chain uses three-aspect logic and skips the preliminary caution.
VERIFIED REPAIR
Show YY when the next signal shows Y, and G only behind YY or G.
Unsuccessful approach: Showing YY behind YY too never lets the chain reach G.
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' 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 = 'G'
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']), ('sampled regression 1', {'occupied': [False, True, False, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'G', 'YY', 'Y']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('control 4', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R']), ('sampled regression 7', {'occupied': [True, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': True}, ['R', 'YY', 'Y', 'R']), ('control 10', {'occupied': [True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['R', 'G'])], [('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 12', {'occupied': [False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('sampled regression 13', {'occupied': [False, True, False, False, False, False, True], 'lamp_fail': [3, 5], 'diverging': [], 'open_end': True}, ['Y', 'R', 'G', 'G', 'YY', 'Y', 'R']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('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']), ('control 21', {'occupied': [True, False, True, False, False, False], 'lamp_fail': [1, 5], 'diverging': [1, 3], 'open_end': True}, ['R', 'Y', 'R', 'Y', 'G', 'G'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 24', {'occupied': [False, False, False, True], 'lamp_fail': [1], 'diverging': [1], 'open_end': True}, ['YY', 'Y', 'Y', 'R']), ('sampled regression 22', {'occupied': [True, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['DARK', 'G', 'YY', 'Y']), ('boundary: open line', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('control 23', {'occupied': [True, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['R', 'Y', 'R']), ('sampled regression 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: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('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']), ('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 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']), ('control 43', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G'])], [('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 47', {'occupied': [False, False, False, False, False], 'lamp_fail': [2], 'diverging': [], 'open_end': False}, ['G', 'G', 'G', 'YY', 'Y']), ('sampled regression 54', {'occupied': [False, False, True, False, False, False, False], 'lamp_fail': [5], 'diverging': [3], 'open_end': False}, ['YY', 'Y', 'R', 'Y', 'G', 'YY', 'Y']), ('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']), ('sampled regression 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('sampled regression 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: buffer stop at the end | ['G', 'G', 'Y'] | ['G', 'YY', 'Y'] | Failed |
| sampled regression 1 | ['Y', 'R', 'G', 'G', 'G', 'Y'] | ['Y', 'R', 'G', 'G', 'YY', 'Y'] | Failed |
| boundary: dark signal ahead | ['R', 'DARK'] | ['R', 'DARK'] | Passed |
| boundary: failed red lamp on a clear signal | ['G', 'G', 'G'] | ['G', 'G', 'G'] | Passed |
| boundary: diverging junction behind a double yellow | ['Y', 'Y', 'R'] | ['Y', 'Y', 'R'] | Passed |
| control 4 | ['Y', 'R'] | ['Y', 'R'] | Passed |
| sampled regression 7 | ['R', 'G', 'Y', 'R'] | ['R', 'YY', 'Y', 'R'] | Failed |
| control 10 | ['R', 'G'] | ['R', 'G'] | Passed |
SHA-256 / 32b32aad03b1e73735c219da045a64a6ad79701a196c209316d5c266275474ae
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 = '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 in ('Y', 'YY'):
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']), ('sampled regression 1', {'occupied': [False, True, False, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'G', 'YY', 'Y']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('control 4', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R']), ('sampled regression 7', {'occupied': [True, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': True}, ['R', 'YY', 'Y', 'R']), ('control 10', {'occupied': [True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['R', 'G'])], [('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 12', {'occupied': [False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('sampled regression 13', {'occupied': [False, True, False, False, False, False, True], 'lamp_fail': [3, 5], 'diverging': [], 'open_end': True}, ['Y', 'R', 'G', 'G', 'YY', 'Y', 'R']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('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']), ('control 21', {'occupied': [True, False, True, False, False, False], 'lamp_fail': [1, 5], 'diverging': [1, 3], 'open_end': True}, ['R', 'Y', 'R', 'Y', 'G', 'G'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 24', {'occupied': [False, False, False, True], 'lamp_fail': [1], 'diverging': [1], 'open_end': True}, ['YY', 'Y', 'Y', 'R']), ('sampled regression 22', {'occupied': [True, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['DARK', 'G', 'YY', 'Y']), ('boundary: open line', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('control 23', {'occupied': [True, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['R', 'Y', 'R']), ('sampled regression 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: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('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']), ('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 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']), ('control 43', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G'])], [('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 47', {'occupied': [False, False, False, False, False], 'lamp_fail': [2], 'diverging': [], 'open_end': False}, ['G', 'G', 'G', 'YY', 'Y']), ('sampled regression 54', {'occupied': [False, False, True, False, False, False, False], 'lamp_fail': [5], 'diverging': [3], 'open_end': False}, ['YY', 'Y', 'R', 'Y', 'G', 'YY', 'Y']), ('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']), ('sampled regression 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('sampled regression 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: buffer stop at the end | ['YY', 'YY', 'Y'] | ['G', 'YY', 'Y'] | Failed |
| sampled regression 1 | ['Y', 'R', 'YY', 'YY', 'YY', 'Y'] | ['Y', 'R', 'G', 'G', 'YY', 'Y'] | Failed |
| boundary: dark signal ahead | ['R', 'DARK'] | ['R', 'DARK'] | Passed |
| boundary: failed red lamp on a clear signal | ['G', 'G', 'G'] | ['G', 'G', 'G'] | Passed |
| boundary: diverging junction behind a double yellow | ['Y', 'Y', 'R'] | ['Y', 'Y', 'R'] | Passed |
| control 4 | ['Y', 'R'] | ['Y', 'R'] | Passed |
| sampled regression 7 | ['R', 'YY', 'Y', 'R'] | ['R', 'YY', 'Y', 'R'] | Passed |
| control 10 | ['R', 'G'] | ['R', 'G'] | Passed |
SHA-256 / 27fdcfd51082f34aeb43086f0602bbd13c82f9bba3c2510b85377795236bc914
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']), ('sampled regression 1', {'occupied': [False, True, False, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['Y', 'R', 'G', 'G', 'YY', 'Y']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('boundary: failed red lamp on a clear signal', {'occupied': [False, False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('control 4', {'occupied': [False, True], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['Y', 'R']), ('sampled regression 7', {'occupied': [True, False, False, True], 'lamp_fail': [], 'diverging': [3], 'open_end': True}, ['R', 'YY', 'Y', 'R']), ('control 10', {'occupied': [True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['R', 'G'])], [('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 12', {'occupied': [False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('sampled regression 13', {'occupied': [False, True, False, False, False, False, True], 'lamp_fail': [3, 5], 'diverging': [], 'open_end': True}, ['Y', 'R', 'G', 'G', 'YY', 'Y', 'R']), ('boundary: diverging junction behind a double yellow', {'occupied': [False, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['Y', 'Y', 'R']), ('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']), ('control 21', {'occupied': [True, False, True, False, False, False], 'lamp_fail': [1, 5], 'diverging': [1, 3], 'open_end': True}, ['R', 'Y', 'R', 'Y', 'G', 'G'])], [('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 24', {'occupied': [False, False, False, True], 'lamp_fail': [1], 'diverging': [1], 'open_end': True}, ['YY', 'Y', 'Y', 'R']), ('sampled regression 22', {'occupied': [True, False, False, False], 'lamp_fail': [0], 'diverging': [], 'open_end': False}, ['DARK', 'G', 'YY', 'Y']), ('boundary: open line', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['G', 'G', 'G']), ('control 23', {'occupied': [True, False, True], 'lamp_fail': [], 'diverging': [0], 'open_end': True}, ['R', 'Y', 'R']), ('sampled regression 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: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('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']), ('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: dark signal at the buffer end', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': False}, ['YY', 'Y']), ('boundary: dark signal ahead', {'occupied': [False, True], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['R', 'DARK']), ('sampled regression 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']), ('control 43', {'occupied': [False, False], 'lamp_fail': [1], 'diverging': [], 'open_end': True}, ['G', 'G'])], [('regression: train two blocks ahead', {'occupied': [False, False, True, False], 'lamp_fail': [], 'diverging': [], 'open_end': True}, ['YY', 'Y', 'R', 'G']), ('regression: buffer stop at the end', {'occupied': [False, False, False], 'lamp_fail': [], 'diverging': [], 'open_end': False}, ['G', 'YY', 'Y']), ('sampled regression 47', {'occupied': [False, False, False, False, False], 'lamp_fail': [2], 'diverging': [], 'open_end': False}, ['G', 'G', 'G', 'YY', 'Y']), ('sampled regression 54', {'occupied': [False, False, True, False, False, False, False], 'lamp_fail': [5], 'diverging': [3], 'open_end': False}, ['YY', 'Y', 'R', 'Y', 'G', 'YY', 'Y']), ('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']), ('sampled regression 48', {'occupied': [False, False, False, False], 'lamp_fail': [1], 'diverging': [2], 'open_end': True}, ['G', 'YY', 'Y', 'G']), ('sampled regression 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: buffer stop at the end | ['G', 'YY', 'Y'] | ['G', 'YY', 'Y'] | Passed |
| sampled regression 1 | ['Y', 'R', 'G', 'G', 'YY', 'Y'] | ['Y', 'R', 'G', 'G', 'YY', 'Y'] | Passed |
| boundary: dark signal ahead | ['R', 'DARK'] | ['R', 'DARK'] | Passed |
| boundary: failed red lamp on a clear signal | ['G', 'G', 'G'] | ['G', 'G', 'G'] | Passed |
| boundary: diverging junction behind a double yellow | ['Y', 'Y', 'R'] | ['Y', 'Y', 'R'] | Passed |
| control 4 | ['Y', 'R'] | ['Y', 'R'] | Passed |
| sampled regression 7 | ['R', 'YY', 'Y', 'R'] | ['R', 'YY', 'Y', 'R'] | Passed |
| control 10 | ['R', 'G'] | ['R', 'G'] | Passed |
SHA-256 / f39c4d5f3a290f7b59df0beb3458bf8677fbeb3bdf1c398d8ffcb6282f6b127e
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.897881+00:00.
Case digest / 55769b29e2da8c8dc9471737bb049f1a967093170d2054004f68cfe2f6f9eb05