FAILURE MAP
← Case archive

FA-92831 / HVAC thermostat control / Open access

Zoned system idles for a minute after a mode is satisfied · case 01

Zones waiting for the opposite mode lose a minute every time the current mode finishes.

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

ROOT CAUSE

Idle mode selection only runs when the system was already idle at the start of the minute.

VERIFIED REPAIR

After a mode ends, choose the next mode in the same minute.

Unsuccessful approach: Skipping selection on the first minute makes a call at power-up wait a minute.

Case contract

Zoned single-unit system arbitration per minute; each sample maps zone -> heat, cool or None. When idle the system picks the mode with more calling zones (ties go to heat). A mode ends when no zone calls for it, and a new mode may be chosen in the same minute. If zones call for the opposite mode, the system switches once the current mode has run max_run minutes, restarting the run timer. Dampers open only for zones calling the active mode. Return [mode, sorted open zones] per minute.

Why this case matters

Residential and light-commercial thermostats make these decisions sample by sample; each defect changes equipment calls in a way that shows up as short cycling, comfort complaints or equipment stress.

1 / The failure

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

N = 1
observations = []
def solve(max_run, samples):
    mode = None
    since = 0
    out = []
    for minute, calls in enumerate(samples):
        heat = sorted(z for z, c in calls.items() if c == 'heat')
        cool = sorted(z for z, c in calls.items() if c == 'cool')
        want = {'heat': heat, 'cool': cool}
        if mode is not None:
            other = 'cool' if mode == 'heat' else 'heat'
            if not want[mode]:
                mode = None
            elif want[other] and minute - since >= max_run:
                mode = other
                since = minute
        elif heat or cool:
            mode = 'heat' if len(heat) >= len(cool) else 'cool'
            since = minute
        out.append([mode, want[mode] if mode else []])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z3': None, 'z4': None},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None, 'z4': 'cool'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'}]],
   [['cool', ['z1']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z4']],
    ['heat', ['z3', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'heat'},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1', 'z3']]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z3': 'heat'}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z1']]]]],
 [['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool'}]],
   [['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: scenario 2',
   [3,
    [{'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'cool'},
     {'z3': 'cool'},
     {'z2': None, 'z3': 'cool', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']]]],
  ['regression: scenario 3',
   [3,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']]]]],
 [['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': None}]],
   [['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z2']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 2',
   [2,
    [{'z1': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z3': None}]],
   [['cool', ['z3', 'z4']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    [None, []]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3', 'z4']],
    ['heat', ['z2', 'z4']]]]],
 [['regression: scenario 2',
   [2,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': None, 'z3': 'cool'}]],
   [['heat', ['z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'heat', 'z4': 'cool'}]],
   [['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z3']],
    ['cool', ['z1']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z3']]]],
  ['regression: scenario 3',
   [5,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z1', 'z4']],
    ['cool', ['z2', 'z3']]]]],
 [['regression: scenario 6',
   [2,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'cool'}]],
   [['heat', ['z2', 'z3']],
    ['heat', ['z2', 'z3']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z2', 'z3']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z3']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat'},
     {'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': None, 'z4': 'heat'},
     {'z2': 'heat', 'z3': None, 'z4': 'heat'}]],
   [['heat', ['z1', 'z2', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z3']],
    ['heat', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2']]]]]]
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: tie goes to heat[['heat', ['a']], ['heat', ['a']], [None, []]][['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]Failed
regression: majority then forced switch[['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]][['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]Passed
regression: ping pong guard[['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']]][['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]Passed
regression: satisfied then opposite[['cool', ['a']], ['cool', ['a']], [None, []], ['heat', ['b']]][['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]Failed
regression: first minute call[['cool', ['a']], ['cool', ['a']], [None, []]][['cool', ['a']], ['cool', ['a']], [None, []]]Passed
regression: scenario 1[['cool', ['z1']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z2', 'z3', 'z4']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z4']], ['heat', ['z3', 'z4']]][['cool', ['z1']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z2', 'z3', 'z4']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z4']], ['heat', ['z3', 'z4']]]Passed
regression: scenario 2[['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1', 'z3']]][['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1', 'z3']]]Passed
regression: scenario 3[['cool', ['z1', 'z3']], ['cool', ['z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['heat', ['z2']], ['heat', ['z2', 'z4']], ['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['cool', ['z1']]][['cool', ['z1', 'z3']], ['cool', ['z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['heat', ['z2']], ['heat', ['z2', 'z4']], ['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['cool', ['z1']]]Passed

SHA-256 / 90ab998fb1f1c1954d89884466d00efa29fd8492bc0945501058ca0aef44c002

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(max_run, samples):
    mode = None
    since = 0
    out = []
    for minute, calls in enumerate(samples):
        heat = sorted(z for z, c in calls.items() if c == 'heat')
        cool = sorted(z for z, c in calls.items() if c == 'cool')
        want = {'heat': heat, 'cool': cool}
        if mode is not None:
            other = 'cool' if mode == 'heat' else 'heat'
            if not want[mode]:
                mode = None
            elif want[other] and minute - since >= max_run:
                mode = other
                since = minute
        if mode is None and (heat or cool) and minute > 0:
            mode = 'heat' if len(heat) >= len(cool) else 'cool'
            since = minute
        out.append([mode, want[mode] if mode else []])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z3': None, 'z4': None},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None, 'z4': 'cool'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'}]],
   [['cool', ['z1']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z4']],
    ['heat', ['z3', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'heat'},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1', 'z3']]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z3': 'heat'}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z1']]]]],
 [['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool'}]],
   [['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: scenario 2',
   [3,
    [{'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'cool'},
     {'z3': 'cool'},
     {'z2': None, 'z3': 'cool', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']]]],
  ['regression: scenario 3',
   [3,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']]]]],
 [['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': None}]],
   [['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z2']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 2',
   [2,
    [{'z1': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z3': None}]],
   [['cool', ['z3', 'z4']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    [None, []]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3', 'z4']],
    ['heat', ['z2', 'z4']]]]],
 [['regression: scenario 2',
   [2,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': None, 'z3': 'cool'}]],
   [['heat', ['z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'heat', 'z4': 'cool'}]],
   [['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z3']],
    ['cool', ['z1']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z3']]]],
  ['regression: scenario 3',
   [5,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z1', 'z4']],
    ['cool', ['z2', 'z3']]]]],
 [['regression: scenario 6',
   [2,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'cool'}]],
   [['heat', ['z2', 'z3']],
    ['heat', ['z2', 'z3']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z2', 'z3']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z3']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat'},
     {'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': None, 'z4': 'heat'},
     {'z2': 'heat', 'z3': None, 'z4': 'heat'}]],
   [['heat', ['z1', 'z2', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z3']],
    ['heat', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2']]]]]]
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: tie goes to heat[[None, []], ['heat', ['a']], ['cool', ['b']]][['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]Failed
regression: majority then forced switch[[None, []], ['heat', ['a']], ['heat', ['a']], ['heat', ['a']], ['heat', ['a']], [None, []]][['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]Failed
regression: ping pong guard[[None, []], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']]][['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]Failed
regression: satisfied then opposite[[None, []], ['heat', ['b']], ['heat', ['b']], ['heat', ['b']]][['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]Failed
regression: first minute call[[None, []], ['cool', ['a']], [None, []]][['cool', ['a']], ['cool', ['a']], [None, []]]Failed
regression: scenario 1[[None, []], ['heat', ['z1', 'z2']], ['heat', ['z1', 'z2', 'z3']], ['heat', ['z1', 'z2', 'z3']], ['heat', ['z1']], ['heat', ['z1']], ['cool', ['z2', 'z4']], ['cool', ['z2', 'z4']], ['cool', ['z2']], ['cool', ['z2']]][['cool', ['z1']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z2', 'z3', 'z4']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z4']], ['heat', ['z3', 'z4']]]Failed
regression: scenario 2[[None, []], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1', 'z3']]][['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1', 'z3']]]Failed
regression: scenario 3[[None, []], ['cool', ['z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['heat', ['z2']], ['heat', ['z2', 'z4']], ['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['cool', ['z1']]][['cool', ['z1', 'z3']], ['cool', ['z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['heat', ['z2']], ['heat', ['z2', 'z4']], ['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['cool', ['z1']]]Failed

SHA-256 / 9b8dbf7bca7e78a695793c4c004762fd3d4a98ba976521e7dc5dd00e2e59fda3

3 / The verified repair

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

N = 1
observations = []
def solve(max_run, samples):
    mode = None
    since = 0
    out = []
    for minute, calls in enumerate(samples):
        heat = sorted(z for z, c in calls.items() if c == 'heat')
        cool = sorted(z for z, c in calls.items() if c == 'cool')
        want = {'heat': heat, 'cool': cool}
        if mode is not None:
            other = 'cool' if mode == 'heat' else 'heat'
            if not want[mode]:
                mode = None
            elif want[other] and minute - since >= max_run:
                mode = other
                since = minute
        if mode is None and (heat or cool):
            mode = 'heat' if len(heat) >= len(cool) else 'cool'
            since = minute
        out.append([mode, want[mode] if mode else []])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z3': None, 'z4': None},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None, 'z4': 'cool'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'}]],
   [['cool', ['z1']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z4']],
    ['heat', ['z3', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'heat'},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1', 'z3']]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z3': 'heat'}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z1']]]]],
 [['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool'}]],
   [['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: scenario 2',
   [3,
    [{'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'cool'},
     {'z3': 'cool'},
     {'z2': None, 'z3': 'cool', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']]]],
  ['regression: scenario 3',
   [3,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']]]]],
 [['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': None}]],
   [['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z2']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 2',
   [2,
    [{'z1': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z3': None}]],
   [['cool', ['z3', 'z4']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    [None, []]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3', 'z4']],
    ['heat', ['z2', 'z4']]]]],
 [['regression: scenario 2',
   [2,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': None, 'z3': 'cool'}]],
   [['heat', ['z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'heat', 'z4': 'cool'}]],
   [['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z3']],
    ['cool', ['z1']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z3']]]],
  ['regression: scenario 3',
   [5,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z1', 'z4']],
    ['cool', ['z2', 'z3']]]]],
 [['regression: scenario 6',
   [2,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'cool'}]],
   [['heat', ['z2', 'z3']],
    ['heat', ['z2', 'z3']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z2', 'z3']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z3']]]],
  ['regression: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat'},
     {'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': None, 'z4': 'heat'},
     {'z2': 'heat', 'z3': None, 'z4': 'heat'}]],
   [['heat', ['z1', 'z2', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z3']],
    ['heat', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2']]]]]]
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: tie goes to heat[['heat', ['a']], ['heat', ['a']], ['cool', ['b']]][['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]Passed
regression: majority then forced switch[['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]][['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]Passed
regression: ping pong guard[['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']]][['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]Passed
regression: satisfied then opposite[['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]][['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]Passed
regression: first minute call[['cool', ['a']], ['cool', ['a']], [None, []]][['cool', ['a']], ['cool', ['a']], [None, []]]Passed
regression: scenario 1[['cool', ['z1']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z2', 'z3', 'z4']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z4']], ['heat', ['z3', 'z4']]][['cool', ['z1']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z4']], ['cool', ['z2', 'z3', 'z4']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z4']], ['heat', ['z3', 'z4']]]Passed
regression: scenario 2[['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1', 'z3']]][['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z3']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1']], ['heat', ['z1', 'z3']]]Passed
regression: scenario 3[['cool', ['z1', 'z3']], ['cool', ['z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['heat', ['z2']], ['heat', ['z2', 'z4']], ['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['cool', ['z1']]][['cool', ['z1', 'z3']], ['cool', ['z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['heat', ['z2']], ['heat', ['z2', 'z4']], ['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z3']], ['heat', ['z3']], ['cool', ['z1']]]Passed

SHA-256 / 79a97142394eb27acfdab0c2907b4e847cece2d0c4dd84f6c21a033c7c7c6ce3

Verification & scope

A deterministic bounded teaching model of one thermostat or HVAC controller decision evaluated per sample. Temperatures are integer tenths of a degree Fahrenheit unless stated otherwise. The contract is a stipulated toy convention, not a claim of conformance to any manufacturer, ASHRAE guideline or code. 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:49.707995+00:00.

Case digest / 74a283eba16052a3ffac7011f22cfd10f5c4b47b568afaf4d45de3b67cacabd9