FA-92271 / PLC ladder logic scan cycles / Open access
Two-hand window rejects a second press exactly at the limit · case 01
Operators pressing the second button right at the synchronous-time limit cannot start the press.
ROOT CAUSE
The synchronous-time test uses < window.
VERIFIED REPAIR
Accept the second button when it arrives within window ms inclusive.
Unsuccessful approach: Requiring the second press to be strictly later rejects a truly simultaneous press.
Case contract
Two-hand press control sampled per scan; samples is a list of [t_ms, left, right]. The press may start only when both buttons become pressed within window ms of the first one being pressed (inclusive), starting from a state where both were released. Releasing either button stops the press, and both buttons must then be released before a new start is allowed (anti-tie-down). Return the run output per scan.
Why this case matters
Ladder programs are executed as repeated scans; each defect here changes what a rung, timer, counter or data-table instruction reports on a particular scan, which is how commissioning and field faults are actually observed.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(window, samples):
first_press = None
armed = True
run = False
out = []
for t, left, right in samples:
left = bool(left)
right = bool(right)
if not left and not right:
armed = True
first_press = None
run = False
elif left and right:
if not run:
begin = t if first_press is None else first_press
if armed and t - begin < window:
run = True
armed = False
else:
run = False
if first_press is None:
first_press = t
out.append(run)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: scenario 1',
[200,
[[0, False, False],
[100, True, True],
[400, True, True],
[500, True, True],
[650, True, True],
[850, True, True],
[1050, True, False],
[1100, False, False],
[1300, True, True],
[1600, True, True]]],
[False, True, True, True, True, True, False, False, True, True]],
['regression: scenario 2',
[200,
[[0, True, True],
[50, True, False],
[200, True, True],
[250, False, False],
[300, False, True],
[400, False, False],
[450, False, False],
[550, False, True]]],
[True, False, False, False, False, False, False, False]],
['regression: scenario 3',
[200,
[[0, True, False],
[150, True, True],
[200, True, True],
[400, False, False],
[500, True, True],
[700, True, True],
[850, True, False],
[1000, True, False],
[1100, False, False],
[1400, True, False],
[1450, False, True],
[1600, True, True],
[1700, True, True]]],
[False, True, True, False, True, True, False, False, False, False, False, True, True]]],
[['regression: scenario 16',
[500,
[[0, True, False],
[50, False, False],
[350, False, True],
[550, True, False],
[850, True, True],
[1050, True, False],
[1150, False, False],
[1250, True, True],
[1550, True, False],
[1700, True, False]]],
[False, False, False, False, True, False, False, True, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: scenario 1',
[250,
[[0, True, True],
[50, True, True],
[200, False, True],
[300, True, True],
[600, True, True],
[750, False, True],
[850, False, False],
[1000, False, True],
[1100, True, True]]],
[True, True, False, False, False, False, False, False, True]],
['regression: scenario 2',
[250,
[[0, True, True],
[50, False, True],
[200, False, False],
[250, True, False],
[400, True, True],
[500, True, True],
[650, False, False],
[700, True, True],
[850, False, False],
[1000, False, True],
[1150, False, True],
[1250, False, True],
[1550, False, False]]],
[True, False, False, False, True, True, False, True, False, False, False, False, False]]],
[['regression: scenario 19',
[500,
[[0, True, False],
[50, True, False],
[350, False, True],
[500, True, True],
[550, True, False],
[650, False, False],
[850, False, False],
[900, True, False],
[1050, True, False]]],
[False, False, False, True, False, False, False, False, False]],
['regression: scenario 2',
[250,
[[0, False, False],
[150, False, False],
[350, False, False],
[400, True, True],
[600, True, False],
[750, False, True],
[1050, True, True],
[1150, True, True],
[1350, True, False],
[1400, False, False],
[1550, True, False]]],
[False, False, False, True, False, False, False, False, False, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['control: scenario 1',
[200,
[[0, False, True],
[100, False, False],
[250, False, False],
[300, True, False],
[400, True, False],
[450, False, True],
[550, True, False],
[700, True, False],
[800, False, True]]],
[False, False, False, False, False, False, False, False, False]]],
[['regression: scenario 55',
[200,
[[0, True, True],
[100, False, False],
[200, True, True],
[250, True, True],
[550, False, False],
[750, True, True],
[850, False, False],
[950, False, True],
[1150, True, True],
[1200, False, False]]],
[True, False, True, True, False, True, False, False, True, False]],
['regression: scenario 2',
[250,
[[0, True, False],
[150, False, False],
[200, True, True],
[350, False, False],
[400, True, False],
[500, False, False],
[800, True, False],
[1000, True, False],
[1050, False, False],
[1100, True, False],
[1400, False, False],
[1450, False, False],
[1600, False, True],
[1800, True, False]]],
[False, False, True, False, False, False, False, False, False, False, False, False, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: scenario 1',
[250,
[[0, False, True],
[200, False, False],
[250, True, False],
[550, True, False],
[650, True, True],
[700, True, False],
[900, True, True],
[1100, True, False],
[1200, False, True],
[1300, True, False],
[1450, False, True],
[1650, False, False],
[1800, True, True]]],
[False, False, False, False, False, False, False, False, False, False, False, False, True]]],
[['regression: scenario 13',
[200,
[[0, False, True],
[300, True, True],
[600, False, False],
[700, False, False],
[850, False, True],
[950, True, True],
[1250, True, False],
[1550, False, False],
[1650, False, False],
[1950, True, False],
[2150, True, True],
[2450, True, False],
[2500, False, True]]],
[False, False, False, False, False, True, False, False, False, False, True, False, False]],
['regression: scenario 6',
[250,
[[0, False, True],
[150, True, True],
[300, False, False],
[400, False, True],
[600, True, False],
[650, True, True],
[750, False, False],
[1050, True, True]]],
[False, True, False, False, False, True, False, True]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['control: scenario 1',
[500,
[[0, True, False],
[150, True, False],
[250, True, False],
[300, False, False],
[350, False, True],
[650, False, True],
[850, False, False],
[1150, False, False],
[1350, True, False],
[1650, True, False],
[1800, True, False],
[1850, True, False],
[1900, False, True]]],
[False, False, False, False, False, False, False, False, False, False, False, False, False]]]]
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: exact window | [False, False, False] | [False, True, False] | Failed |
| regression: normal cycle | [False, True, True, False, False, True] | [False, True, True, False, False, True] | Passed |
| control: late second hand | [False, False, False, False, True] | [False, False, False, False, True] | Passed |
| control: tie down one button | [False, True, False, False, False, False] | [False, True, False, False, False, False] | Passed |
| regression: simultaneous press then release one | [True, False, False] | [True, False, False] | Passed |
| regression: scenario 1 | [False, True, True, True, True, True, False, False, True, True] | [False, True, True, True, True, True, False, False, True, True] | Passed |
| regression: scenario 2 | [True, False, False, False, False, False, False, False] | [True, False, False, False, False, False, False, False] | Passed |
| regression: scenario 3 | [False, True, True, False, True, True, False, False, False, False, False, False, False] | [False, True, True, False, True, True, False, False, False, False, False, True, True] | Failed |
SHA-256 / 0b77c40e53f565dd84ae0e497ca31335c6037eafb480510a07712ae1f572d98d
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(window, samples):
first_press = None
armed = True
run = False
out = []
for t, left, right in samples:
left = bool(left)
right = bool(right)
if not left and not right:
armed = True
first_press = None
run = False
elif left and right:
if not run:
begin = t if first_press is None else first_press
if armed and t - begin <= window and t > begin:
run = True
armed = False
else:
run = False
if first_press is None:
first_press = t
out.append(run)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: scenario 1',
[200,
[[0, False, False],
[100, True, True],
[400, True, True],
[500, True, True],
[650, True, True],
[850, True, True],
[1050, True, False],
[1100, False, False],
[1300, True, True],
[1600, True, True]]],
[False, True, True, True, True, True, False, False, True, True]],
['regression: scenario 2',
[200,
[[0, True, True],
[50, True, False],
[200, True, True],
[250, False, False],
[300, False, True],
[400, False, False],
[450, False, False],
[550, False, True]]],
[True, False, False, False, False, False, False, False]],
['regression: scenario 3',
[200,
[[0, True, False],
[150, True, True],
[200, True, True],
[400, False, False],
[500, True, True],
[700, True, True],
[850, True, False],
[1000, True, False],
[1100, False, False],
[1400, True, False],
[1450, False, True],
[1600, True, True],
[1700, True, True]]],
[False, True, True, False, True, True, False, False, False, False, False, True, True]]],
[['regression: scenario 16',
[500,
[[0, True, False],
[50, False, False],
[350, False, True],
[550, True, False],
[850, True, True],
[1050, True, False],
[1150, False, False],
[1250, True, True],
[1550, True, False],
[1700, True, False]]],
[False, False, False, False, True, False, False, True, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: scenario 1',
[250,
[[0, True, True],
[50, True, True],
[200, False, True],
[300, True, True],
[600, True, True],
[750, False, True],
[850, False, False],
[1000, False, True],
[1100, True, True]]],
[True, True, False, False, False, False, False, False, True]],
['regression: scenario 2',
[250,
[[0, True, True],
[50, False, True],
[200, False, False],
[250, True, False],
[400, True, True],
[500, True, True],
[650, False, False],
[700, True, True],
[850, False, False],
[1000, False, True],
[1150, False, True],
[1250, False, True],
[1550, False, False]]],
[True, False, False, False, True, True, False, True, False, False, False, False, False]]],
[['regression: scenario 19',
[500,
[[0, True, False],
[50, True, False],
[350, False, True],
[500, True, True],
[550, True, False],
[650, False, False],
[850, False, False],
[900, True, False],
[1050, True, False]]],
[False, False, False, True, False, False, False, False, False]],
['regression: scenario 2',
[250,
[[0, False, False],
[150, False, False],
[350, False, False],
[400, True, True],
[600, True, False],
[750, False, True],
[1050, True, True],
[1150, True, True],
[1350, True, False],
[1400, False, False],
[1550, True, False]]],
[False, False, False, True, False, False, False, False, False, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['control: scenario 1',
[200,
[[0, False, True],
[100, False, False],
[250, False, False],
[300, True, False],
[400, True, False],
[450, False, True],
[550, True, False],
[700, True, False],
[800, False, True]]],
[False, False, False, False, False, False, False, False, False]]],
[['regression: scenario 55',
[200,
[[0, True, True],
[100, False, False],
[200, True, True],
[250, True, True],
[550, False, False],
[750, True, True],
[850, False, False],
[950, False, True],
[1150, True, True],
[1200, False, False]]],
[True, False, True, True, False, True, False, False, True, False]],
['regression: scenario 2',
[250,
[[0, True, False],
[150, False, False],
[200, True, True],
[350, False, False],
[400, True, False],
[500, False, False],
[800, True, False],
[1000, True, False],
[1050, False, False],
[1100, True, False],
[1400, False, False],
[1450, False, False],
[1600, False, True],
[1800, True, False]]],
[False, False, True, False, False, False, False, False, False, False, False, False, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: scenario 1',
[250,
[[0, False, True],
[200, False, False],
[250, True, False],
[550, True, False],
[650, True, True],
[700, True, False],
[900, True, True],
[1100, True, False],
[1200, False, True],
[1300, True, False],
[1450, False, True],
[1650, False, False],
[1800, True, True]]],
[False, False, False, False, False, False, False, False, False, False, False, False, True]]],
[['regression: scenario 13',
[200,
[[0, False, True],
[300, True, True],
[600, False, False],
[700, False, False],
[850, False, True],
[950, True, True],
[1250, True, False],
[1550, False, False],
[1650, False, False],
[1950, True, False],
[2150, True, True],
[2450, True, False],
[2500, False, True]]],
[False, False, False, False, False, True, False, False, False, False, True, False, False]],
['regression: scenario 6',
[250,
[[0, False, True],
[150, True, True],
[300, False, False],
[400, False, True],
[600, True, False],
[650, True, True],
[750, False, False],
[1050, True, True]]],
[False, True, False, False, False, True, False, True]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['control: scenario 1',
[500,
[[0, True, False],
[150, True, False],
[250, True, False],
[300, False, False],
[350, False, True],
[650, False, True],
[850, False, False],
[1150, False, False],
[1350, True, False],
[1650, True, False],
[1800, True, False],
[1850, True, False],
[1900, False, True]]],
[False, False, False, False, False, False, False, False, False, False, False, False, False]]]]
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: exact window | [False, True, False] | [False, True, False] | Passed |
| regression: normal cycle | [False, True, True, False, False, False] | [False, True, True, False, False, True] | Failed |
| control: late second hand | [False, False, False, False, True] | [False, False, False, False, True] | Passed |
| control: tie down one button | [False, True, False, False, False, False] | [False, True, False, False, False, False] | Passed |
| regression: simultaneous press then release one | [False, False, False] | [True, False, False] | Failed |
| regression: scenario 1 | [False, False, False, False, False, False, False, False, False, False] | [False, True, True, True, True, True, False, False, True, True] | Failed |
| regression: scenario 2 | [False, False, False, False, False, False, False, False] | [True, False, False, False, False, False, False, False] | Failed |
| regression: scenario 3 | [False, True, True, False, False, False, False, False, False, False, False, True, True] | [False, True, True, False, True, True, False, False, False, False, False, True, True] | Failed |
SHA-256 / 31fbab3b149bedf26826f78058e3351ad6f921ece0f8d11b4e4c43a9e59c9615
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(window, samples):
first_press = None
armed = True
run = False
out = []
for t, left, right in samples:
left = bool(left)
right = bool(right)
if not left and not right:
armed = True
first_press = None
run = False
elif left and right:
if not run:
begin = t if first_press is None else first_press
if armed and t - begin <= window:
run = True
armed = False
else:
run = False
if first_press is None:
first_press = t
out.append(run)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: scenario 1',
[200,
[[0, False, False],
[100, True, True],
[400, True, True],
[500, True, True],
[650, True, True],
[850, True, True],
[1050, True, False],
[1100, False, False],
[1300, True, True],
[1600, True, True]]],
[False, True, True, True, True, True, False, False, True, True]],
['regression: scenario 2',
[200,
[[0, True, True],
[50, True, False],
[200, True, True],
[250, False, False],
[300, False, True],
[400, False, False],
[450, False, False],
[550, False, True]]],
[True, False, False, False, False, False, False, False]],
['regression: scenario 3',
[200,
[[0, True, False],
[150, True, True],
[200, True, True],
[400, False, False],
[500, True, True],
[700, True, True],
[850, True, False],
[1000, True, False],
[1100, False, False],
[1400, True, False],
[1450, False, True],
[1600, True, True],
[1700, True, True]]],
[False, True, True, False, True, True, False, False, False, False, False, True, True]]],
[['regression: scenario 16',
[500,
[[0, True, False],
[50, False, False],
[350, False, True],
[550, True, False],
[850, True, True],
[1050, True, False],
[1150, False, False],
[1250, True, True],
[1550, True, False],
[1700, True, False]]],
[False, False, False, False, True, False, False, True, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: scenario 1',
[250,
[[0, True, True],
[50, True, True],
[200, False, True],
[300, True, True],
[600, True, True],
[750, False, True],
[850, False, False],
[1000, False, True],
[1100, True, True]]],
[True, True, False, False, False, False, False, False, True]],
['regression: scenario 2',
[250,
[[0, True, True],
[50, False, True],
[200, False, False],
[250, True, False],
[400, True, True],
[500, True, True],
[650, False, False],
[700, True, True],
[850, False, False],
[1000, False, True],
[1150, False, True],
[1250, False, True],
[1550, False, False]]],
[True, False, False, False, True, True, False, True, False, False, False, False, False]]],
[['regression: scenario 19',
[500,
[[0, True, False],
[50, True, False],
[350, False, True],
[500, True, True],
[550, True, False],
[650, False, False],
[850, False, False],
[900, True, False],
[1050, True, False]]],
[False, False, False, True, False, False, False, False, False]],
['regression: scenario 2',
[250,
[[0, False, False],
[150, False, False],
[350, False, False],
[400, True, True],
[600, True, False],
[750, False, True],
[1050, True, True],
[1150, True, True],
[1350, True, False],
[1400, False, False],
[1550, True, False]]],
[False, False, False, True, False, False, False, False, False, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['control: scenario 1',
[200,
[[0, False, True],
[100, False, False],
[250, False, False],
[300, True, False],
[400, True, False],
[450, False, True],
[550, True, False],
[700, True, False],
[800, False, True]]],
[False, False, False, False, False, False, False, False, False]]],
[['regression: scenario 55',
[200,
[[0, True, True],
[100, False, False],
[200, True, True],
[250, True, True],
[550, False, False],
[750, True, True],
[850, False, False],
[950, False, True],
[1150, True, True],
[1200, False, False]]],
[True, False, True, True, False, True, False, False, True, False]],
['regression: scenario 2',
[250,
[[0, True, False],
[150, False, False],
[200, True, True],
[350, False, False],
[400, True, False],
[500, False, False],
[800, True, False],
[1000, True, False],
[1050, False, False],
[1100, True, False],
[1400, False, False],
[1450, False, False],
[1600, False, True],
[1800, True, False]]],
[False, False, True, False, False, False, False, False, False, False, False, False, False, False]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['regression: scenario 1',
[250,
[[0, False, True],
[200, False, False],
[250, True, False],
[550, True, False],
[650, True, True],
[700, True, False],
[900, True, True],
[1100, True, False],
[1200, False, True],
[1300, True, False],
[1450, False, True],
[1650, False, False],
[1800, True, True]]],
[False, False, False, False, False, False, False, False, False, False, False, False, True]]],
[['regression: scenario 13',
[200,
[[0, False, True],
[300, True, True],
[600, False, False],
[700, False, False],
[850, False, True],
[950, True, True],
[1250, True, False],
[1550, False, False],
[1650, False, False],
[1950, True, False],
[2150, True, True],
[2450, True, False],
[2500, False, True]]],
[False, False, False, False, False, True, False, False, False, False, True, False, False]],
['regression: scenario 6',
[250,
[[0, False, True],
[150, True, True],
[300, False, False],
[400, False, True],
[600, True, False],
[650, True, True],
[750, False, False],
[1050, True, True]]],
[False, True, False, False, False, True, False, True]],
['regression: normal cycle',
[500,
[[0, True, False],
[300, True, True],
[400, True, True],
[500, False, True],
[600, False, False],
[700, True, True]]],
[False, True, True, False, False, True]],
['control: late second hand',
[200, [[0, True, False], [300, True, True], [400, False, False], [500, True, False], [600, True, True]]],
[False, False, False, False, True]],
['regression: exact window',
[200, [[0, False, True], [200, True, True], [300, False, False]]],
[False, True, False]],
['control: tie down one button',
[200,
[[0, True, False],
[100, True, True],
[200, True, False],
[300, True, True],
[400, True, False],
[450, True, True]]],
[False, True, False, False, False, False]],
['regression: simultaneous press then release one',
[200, [[0, True, True], [100, True, False], [200, True, True]]],
[True, False, False]],
['control: scenario 1',
[500,
[[0, True, False],
[150, True, False],
[250, True, False],
[300, False, False],
[350, False, True],
[650, False, True],
[850, False, False],
[1150, False, False],
[1350, True, False],
[1650, True, False],
[1800, True, False],
[1850, True, False],
[1900, False, True]]],
[False, False, False, False, False, False, False, False, False, False, False, False, False]]]]
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: exact window | [False, True, False] | [False, True, False] | Passed |
| regression: normal cycle | [False, True, True, False, False, True] | [False, True, True, False, False, True] | Passed |
| control: late second hand | [False, False, False, False, True] | [False, False, False, False, True] | Passed |
| control: tie down one button | [False, True, False, False, False, False] | [False, True, False, False, False, False] | Passed |
| regression: simultaneous press then release one | [True, False, False] | [True, False, False] | Passed |
| regression: scenario 1 | [False, True, True, True, True, True, False, False, True, True] | [False, True, True, True, True, True, False, False, True, True] | Passed |
| regression: scenario 2 | [True, False, False, False, False, False, False, False] | [True, False, False, False, False, False, False, False] | Passed |
| regression: scenario 3 | [False, True, True, False, True, True, False, False, False, False, False, True, True] | [False, True, True, False, True, True, False, False, False, False, False, True, True] | Passed |
SHA-256 / 1860ee55cf6c89a57201762def659ed6c9110a4e4f5726a79736430f92ae2dd3
Verification & scope
A deterministic bounded teaching model of one PLC instruction or rung pattern evaluated scan by scan. The stated contract is a stipulated toy convention, not a claim of conformance to any vendor controller or IEC 61131-3 runtime. 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:51:44.254241+00:00.
Case digest / 40c50f04c7324310f53c447c67674265a64d1c022519d7d86b42b016737b48b1