FA-67651 / Elevator dispatch scheduling / Open access
Door obstruction reopen and nudging: cycle reset · case 01
Obstructions from the previous door cycle carry over into the next.
ROOT CAUSE
Closing the doors does not reset the obstruction count.
VERIFIED REPAIR
Reset count, nudging and blockage timer when the cycle ends.
Unsuccessful approach: Leaving nudging set makes the next cycle ignore the light curtain from the start.
Case contract
During a door cycle each light-curtain obstruction reopens the doors and counts; the third obstruction, or an obstruction while the curtain has been blocked continuously for 20 s or more since the first unbroken obstruction, starts nudging (slow close, curtain ignored). While nudging, curtain obstructions are ignored. The mechanical safety edge always reopens and does not affect counting. unblock ends a continuous blockage. closed ends the cycle and resets everything.
Why this case matters
Lift group controllers make these decisions many times per minute; a wrong answer strands passengers, wastes trips or overrides a safety rule.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
count = 0
nudge = False
block_start = None
out = []
for t, ev in x['events']:
if ev == 'obstruct':
if block_start is None:
block_start = t
if nudge:
out.append('ignored')
else:
count += 1
if count >= 3 or t - block_start >= 20:
nudge = True
out.append('nudge')
else:
out.append('reopen')
elif ev == 'unblock':
block_start = None
elif ev == 'edge':
out.append('reopen')
elif ev == 'closed':
nudge = False
block_start = None
out.append('done')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 11', {'events': [[8, 'unblock'], [13, 'obstruct'], [18, 'closed'], [23, 'obstruct'], [35, 'obstruct']]}, ['reopen', 'done', 'reopen', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: third obstruction', {'events': [[1, 'obstruct'], [2, 'unblock'], [3, 'obstruct'], [4, 'unblock'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('sampled regression 1', {'events': [[8, 'obstruct'], [13, 'closed'], [18, 'obstruct'], [26, 'edge'], [28, 'obstruct'], [29, 'obstruct'], [41, 'obstruct'], [42, 'obstruct'], [54, 'obstruct'], [66, 'closed']]}, ['reopen', 'done', 'reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'done']), ('control 4', {'events': [[5, 'edge'], [10, 'unblock'], [11, 'obstruct'], [19, 'closed']]}, ['reopen', 'reopen', 'done']), ('control 7', {'events': [[2, 'unblock'], [10, 'edge'], [18, 'obstruct'], [23, 'unblock'], [28, 'edge'], [33, 'obstruct']]}, ['reopen', 'reopen', 'reopen', 'reopen'])], [('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 47', {'events': [[2, 'edge'], [10, 'obstruct'], [15, 'closed'], [20, 'unblock'], [28, 'obstruct'], [29, 'closed'], [41, 'edge'], [42, 'obstruct'], [43, 'closed'], [55, 'edge']]}, ['reopen', 'reopen', 'done', 'reopen', 'done', 'reopen', 'reopen', 'done', 'reopen']), ('boundary: edge contacts do not count', {'events': [[1, 'obstruct'], [2, 'edge'], [3, 'unblock'], [4, 'obstruct'], [5, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen']), ('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('boundary: curtain held for twenty seconds', {'events': [[0, 'obstruct'], [20, 'obstruct']]}, ['reopen', 'nudge']), ('sampled regression 12', {'events': [[5, 'obstruct'], [13, 'edge'], [15, 'unblock'], [16, 'obstruct'], [21, 'unblock'], [22, 'edge'], [30, 'closed'], [32, 'obstruct'], [44, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen', 'done', 'reopen', 'reopen']), ('control 15', {'events': [[8, 'obstruct'], [9, 'obstruct'], [10, 'obstruct'], [11, 'unblock'], [16, 'obstruct'], [24, 'obstruct'], [29, 'edge']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'reopen']), ('control 18', {'events': [[12, 'obstruct'], [20, 'obstruct'], [22, 'obstruct']]}, ['reopen', 'reopen', 'nudge'])], [('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 69', {'events': [[2, 'unblock'], [14, 'edge'], [15, 'obstruct'], [16, 'obstruct'], [28, 'obstruct'], [36, 'obstruct'], [38, 'obstruct'], [50, 'closed'], [55, 'edge'], [56, 'obstruct']]}, ['reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: curtain held for twenty seconds', {'events': [[0, 'obstruct'], [20, 'obstruct']]}, ['reopen', 'nudge']), ('boundary: curtain broken then blocked again', {'events': [[0, 'obstruct'], [5, 'unblock'], [15, 'obstruct'], [26, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('control 23', {'events': [[1, 'unblock'], [6, 'unblock'], [18, 'obstruct'], [30, 'closed']]}, ['reopen', 'done']), ('control 26', {'events': [[12, 'closed'], [13, 'closed'], [15, 'obstruct'], [17, 'obstruct'], [19, 'obstruct']]}, ['done', 'done', 'reopen', 'reopen', 'nudge']), ('control 29', {'events': [[8, 'edge'], [10, 'obstruct'], [12, 'obstruct'], [20, 'closed']]}, ['reopen', 'reopen', 'reopen', 'done'])], [('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 25', {'events': [[2, 'obstruct'], [10, 'obstruct'], [18, 'closed'], [20, 'obstruct']]}, ['reopen', 'reopen', 'done', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: third obstruction', {'events': [[1, 'obstruct'], [2, 'unblock'], [3, 'obstruct'], [4, 'unblock'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('boundary: safety edge while nudging', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'obstruct'], [4, 'edge'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'reopen', 'ignored']), ('sampled regression 34', {'events': [[8, 'edge'], [16, 'obstruct'], [24, 'obstruct'], [36, 'closed'], [48, 'obstruct'], [60, 'obstruct'], [62, 'obstruct'], [64, 'unblock'], [72, 'obstruct'], [80, 'unblock']]}, ['reopen', 'reopen', 'reopen', 'done', 'reopen', 'reopen', 'nudge', 'ignored']), ('control 37', {'events': [[2, 'closed'], [4, 'closed'], [9, 'obstruct'], [21, 'edge']]}, ['done', 'done', 'reopen', 'reopen']), ('control 40', {'events': [[2, 'closed'], [7, 'obstruct'], [15, 'edge'], [16, 'obstruct'], [18, 'closed']]}, ['done', 'reopen', 'reopen', 'reopen', 'done'])], [('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: safety edge while nudging', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'obstruct'], [4, 'edge'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'reopen', 'ignored']), ('boundary: edge contacts do not count', {'events': [[1, 'obstruct'], [2, 'edge'], [3, 'unblock'], [4, 'obstruct'], [5, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen']), ('control 45', {'events': [[5, 'edge'], [17, 'closed'], [22, 'obstruct'], [24, 'closed']]}, ['reopen', 'done', 'reopen', 'done']), ('control 48', {'events': [[2, 'obstruct'], [7, 'obstruct'], [15, 'obstruct'], [27, 'obstruct'], [35, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored']), ('control 51', {'events': [[8, 'closed'], [9, 'closed'], [14, 'obstruct'], [26, 'closed'], [38, 'obstruct']]}, ['done', 'done', 'reopen', 'done', 'reopen'])]]
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: new cycle after closing | ['reopen', 'reopen', 'done', 'nudge'] | ['reopen', 'reopen', 'done', 'reopen'] | Failed |
| regression: closing clears nudging | ['reopen', 'reopen', 'nudge', 'done', 'nudge'] | ['reopen', 'reopen', 'nudge', 'done', 'reopen'] | Failed |
| sampled regression 11 | ['reopen', 'done', 'reopen', 'nudge'] | ['reopen', 'done', 'reopen', 'reopen'] | Failed |
| sampled regression 68 | ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'nudge', 'reopen'] | ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen'] | Failed |
| boundary: third obstruction | ['reopen', 'reopen', 'nudge'] | ['reopen', 'reopen', 'nudge'] | Passed |
| sampled regression 1 | ['reopen', 'done', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'ignored', 'done'] | ['reopen', 'done', 'reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'done'] | Failed |
| control 4 | ['reopen', 'reopen', 'done'] | ['reopen', 'reopen', 'done'] | Passed |
| control 7 | ['reopen', 'reopen', 'reopen', 'reopen'] | ['reopen', 'reopen', 'reopen', 'reopen'] | Passed |
SHA-256 / f2d5124b20c3d5efe6a1edc20a21450908f3be886aecdf9368e5a2668837c2ff
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
count = 0
nudge = False
block_start = None
out = []
for t, ev in x['events']:
if ev == 'obstruct':
if block_start is None:
block_start = t
if nudge:
out.append('ignored')
else:
count += 1
if count >= 3 or t - block_start >= 20:
nudge = True
out.append('nudge')
else:
out.append('reopen')
elif ev == 'unblock':
block_start = None
elif ev == 'edge':
out.append('reopen')
elif ev == 'closed':
count = 0
block_start = None
out.append('done')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 11', {'events': [[8, 'unblock'], [13, 'obstruct'], [18, 'closed'], [23, 'obstruct'], [35, 'obstruct']]}, ['reopen', 'done', 'reopen', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: third obstruction', {'events': [[1, 'obstruct'], [2, 'unblock'], [3, 'obstruct'], [4, 'unblock'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('sampled regression 1', {'events': [[8, 'obstruct'], [13, 'closed'], [18, 'obstruct'], [26, 'edge'], [28, 'obstruct'], [29, 'obstruct'], [41, 'obstruct'], [42, 'obstruct'], [54, 'obstruct'], [66, 'closed']]}, ['reopen', 'done', 'reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'done']), ('control 4', {'events': [[5, 'edge'], [10, 'unblock'], [11, 'obstruct'], [19, 'closed']]}, ['reopen', 'reopen', 'done']), ('control 7', {'events': [[2, 'unblock'], [10, 'edge'], [18, 'obstruct'], [23, 'unblock'], [28, 'edge'], [33, 'obstruct']]}, ['reopen', 'reopen', 'reopen', 'reopen'])], [('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 47', {'events': [[2, 'edge'], [10, 'obstruct'], [15, 'closed'], [20, 'unblock'], [28, 'obstruct'], [29, 'closed'], [41, 'edge'], [42, 'obstruct'], [43, 'closed'], [55, 'edge']]}, ['reopen', 'reopen', 'done', 'reopen', 'done', 'reopen', 'reopen', 'done', 'reopen']), ('boundary: edge contacts do not count', {'events': [[1, 'obstruct'], [2, 'edge'], [3, 'unblock'], [4, 'obstruct'], [5, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen']), ('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('boundary: curtain held for twenty seconds', {'events': [[0, 'obstruct'], [20, 'obstruct']]}, ['reopen', 'nudge']), ('sampled regression 12', {'events': [[5, 'obstruct'], [13, 'edge'], [15, 'unblock'], [16, 'obstruct'], [21, 'unblock'], [22, 'edge'], [30, 'closed'], [32, 'obstruct'], [44, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen', 'done', 'reopen', 'reopen']), ('control 15', {'events': [[8, 'obstruct'], [9, 'obstruct'], [10, 'obstruct'], [11, 'unblock'], [16, 'obstruct'], [24, 'obstruct'], [29, 'edge']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'reopen']), ('control 18', {'events': [[12, 'obstruct'], [20, 'obstruct'], [22, 'obstruct']]}, ['reopen', 'reopen', 'nudge'])], [('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 69', {'events': [[2, 'unblock'], [14, 'edge'], [15, 'obstruct'], [16, 'obstruct'], [28, 'obstruct'], [36, 'obstruct'], [38, 'obstruct'], [50, 'closed'], [55, 'edge'], [56, 'obstruct']]}, ['reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: curtain held for twenty seconds', {'events': [[0, 'obstruct'], [20, 'obstruct']]}, ['reopen', 'nudge']), ('boundary: curtain broken then blocked again', {'events': [[0, 'obstruct'], [5, 'unblock'], [15, 'obstruct'], [26, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('control 23', {'events': [[1, 'unblock'], [6, 'unblock'], [18, 'obstruct'], [30, 'closed']]}, ['reopen', 'done']), ('control 26', {'events': [[12, 'closed'], [13, 'closed'], [15, 'obstruct'], [17, 'obstruct'], [19, 'obstruct']]}, ['done', 'done', 'reopen', 'reopen', 'nudge']), ('control 29', {'events': [[8, 'edge'], [10, 'obstruct'], [12, 'obstruct'], [20, 'closed']]}, ['reopen', 'reopen', 'reopen', 'done'])], [('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 25', {'events': [[2, 'obstruct'], [10, 'obstruct'], [18, 'closed'], [20, 'obstruct']]}, ['reopen', 'reopen', 'done', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: third obstruction', {'events': [[1, 'obstruct'], [2, 'unblock'], [3, 'obstruct'], [4, 'unblock'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('boundary: safety edge while nudging', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'obstruct'], [4, 'edge'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'reopen', 'ignored']), ('sampled regression 34', {'events': [[8, 'edge'], [16, 'obstruct'], [24, 'obstruct'], [36, 'closed'], [48, 'obstruct'], [60, 'obstruct'], [62, 'obstruct'], [64, 'unblock'], [72, 'obstruct'], [80, 'unblock']]}, ['reopen', 'reopen', 'reopen', 'done', 'reopen', 'reopen', 'nudge', 'ignored']), ('control 37', {'events': [[2, 'closed'], [4, 'closed'], [9, 'obstruct'], [21, 'edge']]}, ['done', 'done', 'reopen', 'reopen']), ('control 40', {'events': [[2, 'closed'], [7, 'obstruct'], [15, 'edge'], [16, 'obstruct'], [18, 'closed']]}, ['done', 'reopen', 'reopen', 'reopen', 'done'])], [('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: safety edge while nudging', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'obstruct'], [4, 'edge'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'reopen', 'ignored']), ('boundary: edge contacts do not count', {'events': [[1, 'obstruct'], [2, 'edge'], [3, 'unblock'], [4, 'obstruct'], [5, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen']), ('control 45', {'events': [[5, 'edge'], [17, 'closed'], [22, 'obstruct'], [24, 'closed']]}, ['reopen', 'done', 'reopen', 'done']), ('control 48', {'events': [[2, 'obstruct'], [7, 'obstruct'], [15, 'obstruct'], [27, 'obstruct'], [35, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored']), ('control 51', {'events': [[8, 'closed'], [9, 'closed'], [14, 'obstruct'], [26, 'closed'], [38, 'obstruct']]}, ['done', 'done', 'reopen', 'done', 'reopen'])]]
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: new cycle after closing | ['reopen', 'reopen', 'done', 'reopen'] | ['reopen', 'reopen', 'done', 'reopen'] | Passed |
| regression: closing clears nudging | ['reopen', 'reopen', 'nudge', 'done', 'ignored'] | ['reopen', 'reopen', 'nudge', 'done', 'reopen'] | Failed |
| sampled regression 11 | ['reopen', 'done', 'reopen', 'reopen'] | ['reopen', 'done', 'reopen', 'reopen'] | Passed |
| sampled regression 68 | ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'ignored', 'reopen'] | ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen'] | Failed |
| boundary: third obstruction | ['reopen', 'reopen', 'nudge'] | ['reopen', 'reopen', 'nudge'] | Passed |
| sampled regression 1 | ['reopen', 'done', 'reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'done'] | ['reopen', 'done', 'reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'done'] | Passed |
| control 4 | ['reopen', 'reopen', 'done'] | ['reopen', 'reopen', 'done'] | Passed |
| control 7 | ['reopen', 'reopen', 'reopen', 'reopen'] | ['reopen', 'reopen', 'reopen', 'reopen'] | Passed |
SHA-256 / 4739b0d6b2d68b721639faf46f04290a52b2116c9bcd2f166916aae5941a4c69
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
count = 0
nudge = False
block_start = None
out = []
for t, ev in x['events']:
if ev == 'obstruct':
if block_start is None:
block_start = t
if nudge:
out.append('ignored')
else:
count += 1
if count >= 3 or t - block_start >= 20:
nudge = True
out.append('nudge')
else:
out.append('reopen')
elif ev == 'unblock':
block_start = None
elif ev == 'edge':
out.append('reopen')
elif ev == 'closed':
count = 0
nudge = False
block_start = None
out.append('done')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 11', {'events': [[8, 'unblock'], [13, 'obstruct'], [18, 'closed'], [23, 'obstruct'], [35, 'obstruct']]}, ['reopen', 'done', 'reopen', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: third obstruction', {'events': [[1, 'obstruct'], [2, 'unblock'], [3, 'obstruct'], [4, 'unblock'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('sampled regression 1', {'events': [[8, 'obstruct'], [13, 'closed'], [18, 'obstruct'], [26, 'edge'], [28, 'obstruct'], [29, 'obstruct'], [41, 'obstruct'], [42, 'obstruct'], [54, 'obstruct'], [66, 'closed']]}, ['reopen', 'done', 'reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'done']), ('control 4', {'events': [[5, 'edge'], [10, 'unblock'], [11, 'obstruct'], [19, 'closed']]}, ['reopen', 'reopen', 'done']), ('control 7', {'events': [[2, 'unblock'], [10, 'edge'], [18, 'obstruct'], [23, 'unblock'], [28, 'edge'], [33, 'obstruct']]}, ['reopen', 'reopen', 'reopen', 'reopen'])], [('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 47', {'events': [[2, 'edge'], [10, 'obstruct'], [15, 'closed'], [20, 'unblock'], [28, 'obstruct'], [29, 'closed'], [41, 'edge'], [42, 'obstruct'], [43, 'closed'], [55, 'edge']]}, ['reopen', 'reopen', 'done', 'reopen', 'done', 'reopen', 'reopen', 'done', 'reopen']), ('boundary: edge contacts do not count', {'events': [[1, 'obstruct'], [2, 'edge'], [3, 'unblock'], [4, 'obstruct'], [5, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen']), ('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('boundary: curtain held for twenty seconds', {'events': [[0, 'obstruct'], [20, 'obstruct']]}, ['reopen', 'nudge']), ('sampled regression 12', {'events': [[5, 'obstruct'], [13, 'edge'], [15, 'unblock'], [16, 'obstruct'], [21, 'unblock'], [22, 'edge'], [30, 'closed'], [32, 'obstruct'], [44, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen', 'done', 'reopen', 'reopen']), ('control 15', {'events': [[8, 'obstruct'], [9, 'obstruct'], [10, 'obstruct'], [11, 'unblock'], [16, 'obstruct'], [24, 'obstruct'], [29, 'edge']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'reopen']), ('control 18', {'events': [[12, 'obstruct'], [20, 'obstruct'], [22, 'obstruct']]}, ['reopen', 'reopen', 'nudge'])], [('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 69', {'events': [[2, 'unblock'], [14, 'edge'], [15, 'obstruct'], [16, 'obstruct'], [28, 'obstruct'], [36, 'obstruct'], [38, 'obstruct'], [50, 'closed'], [55, 'edge'], [56, 'obstruct']]}, ['reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: curtain held for twenty seconds', {'events': [[0, 'obstruct'], [20, 'obstruct']]}, ['reopen', 'nudge']), ('boundary: curtain broken then blocked again', {'events': [[0, 'obstruct'], [5, 'unblock'], [15, 'obstruct'], [26, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('control 23', {'events': [[1, 'unblock'], [6, 'unblock'], [18, 'obstruct'], [30, 'closed']]}, ['reopen', 'done']), ('control 26', {'events': [[12, 'closed'], [13, 'closed'], [15, 'obstruct'], [17, 'obstruct'], [19, 'obstruct']]}, ['done', 'done', 'reopen', 'reopen', 'nudge']), ('control 29', {'events': [[8, 'edge'], [10, 'obstruct'], [12, 'obstruct'], [20, 'closed']]}, ['reopen', 'reopen', 'reopen', 'done'])], [('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 25', {'events': [[2, 'obstruct'], [10, 'obstruct'], [18, 'closed'], [20, 'obstruct']]}, ['reopen', 'reopen', 'done', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: third obstruction', {'events': [[1, 'obstruct'], [2, 'unblock'], [3, 'obstruct'], [4, 'unblock'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge']), ('boundary: safety edge while nudging', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'obstruct'], [4, 'edge'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'reopen', 'ignored']), ('sampled regression 34', {'events': [[8, 'edge'], [16, 'obstruct'], [24, 'obstruct'], [36, 'closed'], [48, 'obstruct'], [60, 'obstruct'], [62, 'obstruct'], [64, 'unblock'], [72, 'obstruct'], [80, 'unblock']]}, ['reopen', 'reopen', 'reopen', 'done', 'reopen', 'reopen', 'nudge', 'ignored']), ('control 37', {'events': [[2, 'closed'], [4, 'closed'], [9, 'obstruct'], [21, 'edge']]}, ['done', 'done', 'reopen', 'reopen']), ('control 40', {'events': [[2, 'closed'], [7, 'obstruct'], [15, 'edge'], [16, 'obstruct'], [18, 'closed']]}, ['done', 'reopen', 'reopen', 'reopen', 'done'])], [('regression: new cycle after closing', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct'], [5, 'unblock']]}, ['reopen', 'reopen', 'done', 'reopen']), ('regression: closing clears nudging', {'events': [[0, 'obstruct'], [1, 'obstruct'], [2, 'obstruct'], [3, 'closed'], [4, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'done', 'reopen']), ('sampled regression 68', {'events': [[5, 'obstruct'], [13, 'obstruct'], [18, 'obstruct'], [30, 'obstruct'], [35, 'edge'], [36, 'obstruct'], [48, 'closed'], [53, 'obstruct'], [55, 'edge'], [60, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen']), ('boundary: safety edge while nudging', {'events': [[1, 'obstruct'], [2, 'obstruct'], [3, 'obstruct'], [4, 'edge'], [5, 'obstruct']]}, ['reopen', 'reopen', 'nudge', 'reopen', 'ignored']), ('boundary: edge contacts do not count', {'events': [[1, 'obstruct'], [2, 'edge'], [3, 'unblock'], [4, 'obstruct'], [5, 'edge']]}, ['reopen', 'reopen', 'reopen', 'reopen']), ('control 45', {'events': [[5, 'edge'], [17, 'closed'], [22, 'obstruct'], [24, 'closed']]}, ['reopen', 'done', 'reopen', 'done']), ('control 48', {'events': [[2, 'obstruct'], [7, 'obstruct'], [15, 'obstruct'], [27, 'obstruct'], [35, 'unblock']]}, ['reopen', 'reopen', 'nudge', 'ignored']), ('control 51', {'events': [[8, 'closed'], [9, 'closed'], [14, 'obstruct'], [26, 'closed'], [38, 'obstruct']]}, ['done', 'done', 'reopen', 'done', 'reopen'])]]
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: new cycle after closing | ['reopen', 'reopen', 'done', 'reopen'] | ['reopen', 'reopen', 'done', 'reopen'] | Passed |
| regression: closing clears nudging | ['reopen', 'reopen', 'nudge', 'done', 'reopen'] | ['reopen', 'reopen', 'nudge', 'done', 'reopen'] | Passed |
| sampled regression 11 | ['reopen', 'done', 'reopen', 'reopen'] | ['reopen', 'done', 'reopen', 'reopen'] | Passed |
| sampled regression 68 | ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen'] | ['reopen', 'reopen', 'nudge', 'ignored', 'reopen', 'ignored', 'done', 'reopen', 'reopen'] | Passed |
| boundary: third obstruction | ['reopen', 'reopen', 'nudge'] | ['reopen', 'reopen', 'nudge'] | Passed |
| sampled regression 1 | ['reopen', 'done', 'reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'done'] | ['reopen', 'done', 'reopen', 'reopen', 'reopen', 'nudge', 'ignored', 'ignored', 'ignored', 'done'] | Passed |
| control 4 | ['reopen', 'reopen', 'done'] | ['reopen', 'reopen', 'done'] | Passed |
| control 7 | ['reopen', 'reopen', 'reopen', 'reopen'] | ['reopen', 'reopen', 'reopen', 'reopen'] | Passed |
SHA-256 / 4e18ac160821fa713ece930b25936e124cad322bf6e33df9d03eb6a927b0fa76
Verification & scope
Stipulated toy lift-control contract for a bounded teaching model; it makes no claim of conformance to any lift code or vendor dispatcher 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:54.919168+00:00.
Case digest / 7784f8fc325def1ae93d23adfe1046a8be1d932287166d1125a1273e847c78b5