FAILURE MAP
← Case archive

FA-92311 / PLC ladder logic scan cycles / Open access

Horn keeps sounding for acknowledged alarms · case 01

Acknowledging alarms does not stop the horn while they remain active.

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

ROOT CAUSE

The horn is driven by the active set instead of the unacknowledged set.

VERIFIED REPAIR

Sound the horn only for unacknowledged alarms.

Unsuccessful approach: Sounding only on the activation scan makes the horn a one-scan chirp.

Case contract

Stack light and horn logic. alarms is a list of [name, high|low]; each scan gives the active alarm names plus optional ack and silence buttons. An alarm becomes unacknowledged on its inactive-to-active transition and stops being unacknowledged when it clears or ack is pressed. Any new activation cancels silence; silence (pressed after that) mutes the horn. The lamp is red if any high alarm is active, else amber if any alarm is active, else off; it flashes if an unacknowledged alarm of the displayed level exists. The horn sounds while any unacknowledged alarm exists and not silenced. Return [color, flashing, horn] 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(alarms, scans):
    level = dict(alarms)
    prev = set()
    unacked = set()
    silenced = False
    out = []
    for s in scans:
        active = set(s.get('active', []))
        new = active - prev
        if new:
            silenced = False
        unacked = (unacked | new) & active
        if s.get('ack'):
            unacked = set()
        if s.get('silence'):
            silenced = True
        if any(level[a] == 'high' for a in active):
            shown = 'high'
        elif active:
            shown = 'low'
        else:
            shown = None
        color = {'high': 'red', 'low': 'amber', None: 'off'}[shown]
        flashing = any(level[a] == shown for a in unacked)
        horn = bool(active) and not silenced
        prev = active
        out.append([color, flashing, horn])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['TT300'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['ZS400'], 'ack': True, 'silence': True},
     {'active': []},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'ZS400'], 'ack': True}]],
   [['amber', False, False],
    ['amber', False, False],
    ['red', False, False],
    ['off', False, False],
    ['red', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False]]],
  ['control: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['TT300'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['LT200', 'TT300']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True}]],
   [['amber', True, False],
    ['red', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False]]],
  ['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': [], 'ack': True},
     {'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400'], 'silence': True},
     {'active': ['LT200', 'PT101'], 'ack': True}]],
   [['off', False, False],
    ['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', False, False]]]],
 [['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['ZS400'], 'silence': True},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200']}]],
   [['red', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['amber', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['TT300']},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300'], 'ack': True},
     {'active': ['LT200', 'TT300']}]],
   [['red', True, True],
    ['red', False, False],
    ['amber', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['amber', False, False],
    ['amber', False, False]]],
  ['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['LT200', 'PT101', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400'], 'ack': True},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400']},
     {'active': ['PT101', 'ZS400']},
     {'active': ['PT101', 'ZS400'], 'ack': True},
     {'active': ['PT101', 'ZS400']}]],
   [['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False],
    ['red', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False],
    ['red', False, False]]]],
 [['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['TT300']},
     {'active': ['TT300']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400'], 'ack': True}]],
   [['red', True, False],
    ['red', True, True],
    ['amber', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', False, False]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101']},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101'], 'silence': True},
     {'active': ['LT200', 'PT101']},
     {'active': []},
     {'active': []},
     {'active': []},
     {'active': [], 'ack': True},
     {'active': ['LT200']},
     {'active': ['LT200', 'TT300']}]],
   [['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['amber', True, True],
    ['amber', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400']},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['ZS400']},
     {'active': []},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400']},
     {'active': ['PT101', 'TT300', 'ZS400']}]],
   [['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False],
    ['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True]]]],
 [['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': []},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300'], 'ack': True},
     {'active': ['PT101', 'ZS400'], 'silence': True},
     {'active': ['PT101']},
     {'active': ['PT101'], 'silence': True}]],
   [['off', False, False],
    ['red', True, True],
    ['red', False, False],
    ['red', True, False],
    ['red', False, False],
    ['red', False, False]]],
  ['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['LT200'], 'silence': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300']}]],
   [['amber', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101'], 'ack': True},
     {'active': ['PT101']},
     {'active': ['PT101'], 'ack': True},
     {'active': ['PT101']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300']},
     {'active': ['LT200', 'PT101', 'TT300'], 'ack': True},
     {'active': ['LT200', 'TT300']}]],
   [['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, True],
    ['red', False, False],
    ['amber', False, False]]]],
 [['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['ZS400'], 'ack': True},
     {'active': ['TT300', 'ZS400']},
     {'active': ['PT101', 'TT300', 'ZS400'], 'ack': True},
     {'active': ['PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['ZS400']}]],
   [['red', False, False],
    ['red', False, True],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False]]],
  ['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300']},
     {'active': ['TT300'], 'ack': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['TT300', 'ZS400']},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['PT101', 'ZS400'], 'ack': True},
     {'active': ['LT200', 'PT101', 'ZS400'], 'ack': True, 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']}]],
   [['red', True, True],
    ['red', True, True],
    ['amber', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': [], 'silence': True},
     {'active': [], 'silence': True},
     {'active': [], 'silence': True},
     {'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['PT101', 'TT300'], 'ack': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300']}]],
   [['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', True, True],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', 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 fixtureActualExpectedOutcome
regression: escalation sequence[['amber', True, True], ['amber', True, False], ['red', True, True], ['red', False, True], ['amber', False, True], ['off', False, False]][['amber', True, True], ['amber', True, False], ['red', True, True], ['red', False, False], ['amber', False, False], ['off', False, False]]Failed
regression: low alarm while high acked[['red', False, True], ['red', False, True], ['red', False, False], ['red', False, False]][['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]Failed
control: alarm clears unacknowledged[['red', True, True], ['off', False, False], ['amber', True, True]][['red', True, True], ['off', False, False], ['amber', True, True]]Passed
regression: alarm present at first scan[['red', True, True], ['red', True, True]][['red', True, True], ['red', True, True]]Passed
control: silence then new low alarm[['red', True, True], ['red', True, False], ['red', True, True]][['red', True, True], ['red', True, False], ['red', True, True]]Passed
regression: scenario 1[['amber', False, True], ['amber', False, True], ['red', False, False], ['off', False, False], ['red', True, False], ['red', True, True], ['red', True, True], ['red', True, True], ['red', False, True]][['amber', False, False], ['amber', False, False], ['red', False, False], ['off', False, False], ['red', True, False], ['red', True, True], ['red', True, True], ['red', True, True], ['red', False, False]]Failed
control: scenario 2[['amber', True, False], ['red', True, True], ['amber', True, True], ['red', True, True], ['red', True, False], ['red', True, False]][['amber', True, False], ['red', True, True], ['amber', True, True], ['red', True, True], ['red', True, False], ['red', True, False]]Passed
regression: scenario 3[['off', False, False], ['off', False, False], ['red', True, True], ['red', True, True], ['red', True, False], ['red', False, False]][['off', False, False], ['off', False, False], ['red', True, True], ['red', True, True], ['red', True, False], ['red', False, False]]Passed

SHA-256 / f6c2b1192b2d924f96e9961c31e079b908b89ef93f54703ca09fdbe051b8719c

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(alarms, scans):
    level = dict(alarms)
    prev = set()
    unacked = set()
    silenced = False
    out = []
    for s in scans:
        active = set(s.get('active', []))
        new = active - prev
        if new:
            silenced = False
        unacked = (unacked | new) & active
        if s.get('ack'):
            unacked = set()
        if s.get('silence'):
            silenced = True
        if any(level[a] == 'high' for a in active):
            shown = 'high'
        elif active:
            shown = 'low'
        else:
            shown = None
        color = {'high': 'red', 'low': 'amber', None: 'off'}[shown]
        flashing = any(level[a] == shown for a in unacked)
        horn = bool(new) and not silenced
        prev = active
        out.append([color, flashing, horn])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['TT300'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['ZS400'], 'ack': True, 'silence': True},
     {'active': []},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'ZS400'], 'ack': True}]],
   [['amber', False, False],
    ['amber', False, False],
    ['red', False, False],
    ['off', False, False],
    ['red', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False]]],
  ['control: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['TT300'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['LT200', 'TT300']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True}]],
   [['amber', True, False],
    ['red', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False]]],
  ['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': [], 'ack': True},
     {'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400'], 'silence': True},
     {'active': ['LT200', 'PT101'], 'ack': True}]],
   [['off', False, False],
    ['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', False, False]]]],
 [['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['ZS400'], 'silence': True},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200']}]],
   [['red', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['amber', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['TT300']},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300'], 'ack': True},
     {'active': ['LT200', 'TT300']}]],
   [['red', True, True],
    ['red', False, False],
    ['amber', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['amber', False, False],
    ['amber', False, False]]],
  ['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['LT200', 'PT101', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400'], 'ack': True},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400']},
     {'active': ['PT101', 'ZS400']},
     {'active': ['PT101', 'ZS400'], 'ack': True},
     {'active': ['PT101', 'ZS400']}]],
   [['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False],
    ['red', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False],
    ['red', False, False]]]],
 [['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['TT300']},
     {'active': ['TT300']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400'], 'ack': True}]],
   [['red', True, False],
    ['red', True, True],
    ['amber', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', False, False]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101']},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101'], 'silence': True},
     {'active': ['LT200', 'PT101']},
     {'active': []},
     {'active': []},
     {'active': []},
     {'active': [], 'ack': True},
     {'active': ['LT200']},
     {'active': ['LT200', 'TT300']}]],
   [['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['amber', True, True],
    ['amber', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400']},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['ZS400']},
     {'active': []},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400']},
     {'active': ['PT101', 'TT300', 'ZS400']}]],
   [['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False],
    ['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True]]]],
 [['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': []},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300'], 'ack': True},
     {'active': ['PT101', 'ZS400'], 'silence': True},
     {'active': ['PT101']},
     {'active': ['PT101'], 'silence': True}]],
   [['off', False, False],
    ['red', True, True],
    ['red', False, False],
    ['red', True, False],
    ['red', False, False],
    ['red', False, False]]],
  ['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['LT200'], 'silence': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300']}]],
   [['amber', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101'], 'ack': True},
     {'active': ['PT101']},
     {'active': ['PT101'], 'ack': True},
     {'active': ['PT101']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300']},
     {'active': ['LT200', 'PT101', 'TT300'], 'ack': True},
     {'active': ['LT200', 'TT300']}]],
   [['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, True],
    ['red', False, False],
    ['amber', False, False]]]],
 [['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['ZS400'], 'ack': True},
     {'active': ['TT300', 'ZS400']},
     {'active': ['PT101', 'TT300', 'ZS400'], 'ack': True},
     {'active': ['PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['ZS400']}]],
   [['red', False, False],
    ['red', False, True],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False]]],
  ['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300']},
     {'active': ['TT300'], 'ack': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['TT300', 'ZS400']},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['PT101', 'ZS400'], 'ack': True},
     {'active': ['LT200', 'PT101', 'ZS400'], 'ack': True, 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']}]],
   [['red', True, True],
    ['red', True, True],
    ['amber', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': [], 'silence': True},
     {'active': [], 'silence': True},
     {'active': [], 'silence': True},
     {'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['PT101', 'TT300'], 'ack': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300']}]],
   [['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', True, True],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', 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 fixtureActualExpectedOutcome
regression: escalation sequence[['amber', True, True], ['amber', True, False], ['red', True, True], ['red', False, False], ['amber', False, False], ['off', False, False]][['amber', True, True], ['amber', True, False], ['red', True, True], ['red', False, False], ['amber', False, False], ['off', False, False]]Passed
regression: low alarm while high acked[['red', False, True], ['red', False, True], ['red', False, False], ['red', False, False]][['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]Failed
control: alarm clears unacknowledged[['red', True, True], ['off', False, False], ['amber', True, True]][['red', True, True], ['off', False, False], ['amber', True, True]]Passed
regression: alarm present at first scan[['red', True, True], ['red', True, False]][['red', True, True], ['red', True, True]]Failed
control: silence then new low alarm[['red', True, True], ['red', True, False], ['red', True, True]][['red', True, True], ['red', True, False], ['red', True, True]]Passed
regression: scenario 1[['amber', False, True], ['amber', False, False], ['red', False, False], ['off', False, False], ['red', True, False], ['red', True, True], ['red', True, True], ['red', True, False], ['red', False, False]][['amber', False, False], ['amber', False, False], ['red', False, False], ['off', False, False], ['red', True, False], ['red', True, True], ['red', True, True], ['red', True, True], ['red', False, False]]Failed
control: scenario 2[['amber', True, False], ['red', True, True], ['amber', True, True], ['red', True, True], ['red', True, False], ['red', True, False]][['amber', True, False], ['red', True, True], ['amber', True, True], ['red', True, True], ['red', True, False], ['red', True, False]]Passed
regression: scenario 3[['off', False, False], ['off', False, False], ['red', True, True], ['red', True, False], ['red', True, False], ['red', False, False]][['off', False, False], ['off', False, False], ['red', True, True], ['red', True, True], ['red', True, False], ['red', False, False]]Failed

SHA-256 / 078943947434308a6a5ab0762b2050b90023b72769a91ac1ada0b568890a52c9

3 / The verified repair

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

N = 1
observations = []
def solve(alarms, scans):
    level = dict(alarms)
    prev = set()
    unacked = set()
    silenced = False
    out = []
    for s in scans:
        active = set(s.get('active', []))
        new = active - prev
        if new:
            silenced = False
        unacked = (unacked | new) & active
        if s.get('ack'):
            unacked = set()
        if s.get('silence'):
            silenced = True
        if any(level[a] == 'high' for a in active):
            shown = 'high'
        elif active:
            shown = 'low'
        else:
            shown = None
        color = {'high': 'red', 'low': 'amber', None: 'off'}[shown]
        flashing = any(level[a] == shown for a in unacked)
        horn = bool(unacked) and not silenced
        prev = active
        out.append([color, flashing, horn])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['TT300'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['ZS400'], 'ack': True, 'silence': True},
     {'active': []},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'ZS400'], 'ack': True}]],
   [['amber', False, False],
    ['amber', False, False],
    ['red', False, False],
    ['off', False, False],
    ['red', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False]]],
  ['control: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['TT300'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['LT200', 'TT300']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True}]],
   [['amber', True, False],
    ['red', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False]]],
  ['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': [], 'ack': True},
     {'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400'], 'silence': True},
     {'active': ['LT200', 'PT101'], 'ack': True}]],
   [['off', False, False],
    ['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', False, False]]]],
 [['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['ZS400'], 'silence': True},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200']}]],
   [['red', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['amber', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['TT300']},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101']},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'TT300'], 'ack': True},
     {'active': ['LT200', 'TT300']}]],
   [['red', True, True],
    ['red', False, False],
    ['amber', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['amber', False, False],
    ['amber', False, False]]],
  ['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['LT200', 'PT101', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400'], 'ack': True},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400']},
     {'active': ['PT101', 'ZS400']},
     {'active': ['PT101', 'ZS400'], 'ack': True},
     {'active': ['PT101', 'ZS400']}]],
   [['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False],
    ['red', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', False, False],
    ['red', False, False]]]],
 [['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['TT300']},
     {'active': ['TT300']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400'], 'ack': True}]],
   [['red', True, False],
    ['red', True, True],
    ['amber', True, True],
    ['amber', True, True],
    ['red', True, True],
    ['red', False, False]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101']},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101']},
     {'active': ['LT200', 'PT101'], 'silence': True},
     {'active': ['LT200', 'PT101']},
     {'active': []},
     {'active': []},
     {'active': []},
     {'active': [], 'ack': True},
     {'active': ['LT200']},
     {'active': ['LT200', 'TT300']}]],
   [['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['amber', True, True],
    ['amber', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400']},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['ZS400']},
     {'active': []},
     {'active': ['LT200', 'ZS400']},
     {'active': ['LT200', 'PT101', 'ZS400']},
     {'active': ['PT101', 'TT300', 'ZS400']}]],
   [['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', True, False],
    ['off', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True]]]],
 [['regression: scenario 2',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': []},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300'], 'ack': True},
     {'active': ['PT101', 'ZS400'], 'silence': True},
     {'active': ['PT101']},
     {'active': ['PT101'], 'silence': True}]],
   [['off', False, False],
    ['red', True, True],
    ['red', False, False],
    ['red', True, False],
    ['red', False, False],
    ['red', False, False]]],
  ['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['LT200'], 'silence': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300']}]],
   [['amber', True, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True],
    ['red', True, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101'], 'ack': True},
     {'active': ['PT101']},
     {'active': ['PT101'], 'ack': True},
     {'active': ['PT101']},
     {'active': ['PT101']},
     {'active': ['LT200', 'PT101', 'TT300']},
     {'active': ['LT200', 'PT101', 'TT300'], 'ack': True},
     {'active': ['LT200', 'TT300']}]],
   [['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, True],
    ['red', False, False],
    ['amber', False, False]]]],
 [['regression: scenario 3',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['ZS400'], 'ack': True},
     {'active': ['TT300', 'ZS400']},
     {'active': ['PT101', 'TT300', 'ZS400'], 'ack': True},
     {'active': ['PT101', 'TT300', 'ZS400']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['ZS400']},
     {'active': ['ZS400']}]],
   [['red', False, False],
    ['red', False, True],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False]]],
  ['regression: scenario 4',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300']},
     {'active': ['TT300'], 'ack': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['TT300', 'ZS400']},
     {'active': ['ZS400'], 'silence': True},
     {'active': ['PT101', 'ZS400'], 'ack': True},
     {'active': ['LT200', 'PT101', 'ZS400'], 'ack': True, 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300', 'ZS400']}]],
   [['red', True, True],
    ['red', True, True],
    ['amber', False, False],
    ['red', True, True],
    ['red', True, True],
    ['red', True, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, True]]],
  ['regression: escalation sequence',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['B']},
     {'active': ['B'], 'silence': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'ack': True},
     {'active': ['B']},
     {}]],
   [['amber', True, True],
    ['amber', True, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', False, False],
    ['off', False, False]]],
  ['control: alarm clears unacknowledged',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {}, {'active': ['B']}]],
   [['red', True, True], ['off', False, False], ['amber', True, True]]],
  ['regression: low alarm while high acked',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A'], 'ack': True},
     {'active': ['A', 'B']},
     {'active': ['A', 'B'], 'silence': True},
     {'active': ['A', 'B']}]],
   [['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]],
  ['regression: alarm present at first scan',
   [[['A', 'high'], ['B', 'low']], [{'active': ['A']}, {'active': ['A']}]],
   [['red', True, True], ['red', True, True]]],
  ['control: silence then new low alarm',
   [[['A', 'high'], ['B', 'low']],
    [{'active': ['A']}, {'active': ['A'], 'silence': True}, {'active': ['A', 'B']}]],
   [['red', True, True], ['red', True, False], ['red', True, True]]],
  ['regression: scenario 1',
   [[['PT101', 'high'], ['LT200', 'low'], ['TT300', 'low'], ['ZS400', 'high']],
    [{'active': [], 'silence': True},
     {'active': [], 'silence': True},
     {'active': [], 'silence': True},
     {'active': []},
     {'active': ['ZS400']},
     {'active': ['ZS400'], 'ack': True},
     {'active': ['TT300']},
     {'active': ['PT101', 'TT300'], 'ack': True},
     {'active': ['PT101', 'TT300']},
     {'active': ['PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300'], 'silence': True},
     {'active': ['LT200', 'PT101', 'TT300']}]],
   [['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['off', False, False],
    ['red', True, True],
    ['red', False, False],
    ['amber', True, True],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', False, False],
    ['red', 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 fixtureActualExpectedOutcome
regression: escalation sequence[['amber', True, True], ['amber', True, False], ['red', True, True], ['red', False, False], ['amber', False, False], ['off', False, False]][['amber', True, True], ['amber', True, False], ['red', True, True], ['red', False, False], ['amber', False, False], ['off', False, False]]Passed
regression: low alarm while high acked[['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]][['red', False, False], ['red', False, True], ['red', False, False], ['red', False, False]]Passed
control: alarm clears unacknowledged[['red', True, True], ['off', False, False], ['amber', True, True]][['red', True, True], ['off', False, False], ['amber', True, True]]Passed
regression: alarm present at first scan[['red', True, True], ['red', True, True]][['red', True, True], ['red', True, True]]Passed
control: silence then new low alarm[['red', True, True], ['red', True, False], ['red', True, True]][['red', True, True], ['red', True, False], ['red', True, True]]Passed
regression: scenario 1[['amber', False, False], ['amber', False, False], ['red', False, False], ['off', False, False], ['red', True, False], ['red', True, True], ['red', True, True], ['red', True, True], ['red', False, False]][['amber', False, False], ['amber', False, False], ['red', False, False], ['off', False, False], ['red', True, False], ['red', True, True], ['red', True, True], ['red', True, True], ['red', False, False]]Passed
control: scenario 2[['amber', True, False], ['red', True, True], ['amber', True, True], ['red', True, True], ['red', True, False], ['red', True, False]][['amber', True, False], ['red', True, True], ['amber', True, True], ['red', True, True], ['red', True, False], ['red', True, False]]Passed
regression: scenario 3[['off', False, False], ['off', False, False], ['red', True, True], ['red', True, True], ['red', True, False], ['red', False, False]][['off', False, False], ['off', False, False], ['red', True, True], ['red', True, True], ['red', True, False], ['red', False, False]]Passed

SHA-256 / 0b552ac0d6dcc793462d2370af50900283ff5e1e460c9075ee4cc1e9d4379e08

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

Case digest / 752c275f2c6b8e8a9534d50bb7ad124d83ff55a954f56e4389c4fc85d788c67c