FAILURE MAP
← Case archive

FA-92816 / HVAC thermostat control / Open access

Zoned system picks cooling on a tied zone vote · case 01

With one zone calling heat and one calling cool the system cools first, against the heat-priority rule.

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

ROOT CAUSE

The mode vote uses a strict comparison so ties go to cooling.

VERIFIED REPAIR

Ties go to heat (>=).

Unsuccessful approach: Giving heat priority whenever any zone calls heat ignores a cooling majority.

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
        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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]],
  ['control: 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: 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: 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: 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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]],
  ['control: 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 5',
   [2,
    [{'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': None, 'z4': 'heat'},
     {'z1': 'cool', 'z4': 'heat'},
     {'z1': None},
     {'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None, 'z4': 'heat'}]],
   [['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z4']],
    ['cool', ['z1']],
    ['cool', ['z1']],
    [None, []],
    ['heat', ['z4']],
    ['heat', ['z1', 'z4']],
    ['cool', ['z2']]]],
  ['regression: scenario 14',
   [2,
    [{'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'heat', 'z3': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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: 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: scenario 11',
   [2,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z3': 'heat'},
     {'z1': None},
     {'z1': None, 'z3': None, 'z4': None},
     {'z1': None, 'z4': None},
     {'z2': None, 'z3': None, 'z4': None},
     {'z2': 'cool', 'z3': None},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': None}]],
   [['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z3']],
    [None, []],
    [None, []],
    [None, []],
    [None, []],
    ['cool', ['z2']],
    ['cool', ['z2']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: 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 13',
   [3,
    [{'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z3': 'heat', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z4': 'cool'}]],
   [['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['cool', ['z1']],
    ['cool', ['z1', 'z4']]]],
  ['regression: scenario 7',
   [5,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': None}]],
   [['cool', ['z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z1', 'z4']],
    ['heat', ['z1']],
    ['heat', ['z1']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]]]]
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[['cool', ['b']], ['cool', ['b']], ['cool', ['b']]][['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[['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']]][['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]Failed
control: satisfied then opposite[['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]][['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]Passed
control: first minute call[['cool', ['a']], ['cool', ['a']], [None, []]][['cool', ['a']], ['cool', ['a']], [None, []]]Passed
control: 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
control: 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 / 332e123d25d93e603e8365f79cfcf8366d42322992dde9ad65657a1f64810e06

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):
            mode = 'heat' if heat 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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]],
  ['control: 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: 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: 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: 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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]],
  ['control: 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 5',
   [2,
    [{'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': None, 'z4': 'heat'},
     {'z1': 'cool', 'z4': 'heat'},
     {'z1': None},
     {'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None, 'z4': 'heat'}]],
   [['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z4']],
    ['cool', ['z1']],
    ['cool', ['z1']],
    [None, []],
    ['heat', ['z4']],
    ['heat', ['z1', 'z4']],
    ['cool', ['z2']]]],
  ['regression: scenario 14',
   [2,
    [{'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'heat', 'z3': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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: 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: scenario 11',
   [2,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z3': 'heat'},
     {'z1': None},
     {'z1': None, 'z3': None, 'z4': None},
     {'z1': None, 'z4': None},
     {'z2': None, 'z3': None, 'z4': None},
     {'z2': 'cool', 'z3': None},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': None}]],
   [['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z3']],
    [None, []],
    [None, []],
    [None, []],
    [None, []],
    ['cool', ['z2']],
    ['cool', ['z2']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: 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 13',
   [3,
    [{'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z3': 'heat', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z4': 'cool'}]],
   [['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['cool', ['z1']],
    ['cool', ['z1', 'z4']]]],
  ['regression: scenario 7',
   [5,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': None}]],
   [['cool', ['z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z1', 'z4']],
    ['heat', ['z1']],
    ['heat', ['z1']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]]]]
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[['heat', ['a']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['heat', ['a']], [None, []]][['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]Failed
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
control: satisfied then opposite[['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]][['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]Passed
control: first minute call[['cool', ['a']], ['cool', ['a']], [None, []]][['cool', ['a']], ['cool', ['a']], [None, []]]Passed
control: 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
control: 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[['heat', ['z2']], ['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 / b6a7c6a95a435a868243c3057c161442f6bfdad5cce0838116ef1bfebb0076cf

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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]],
  ['control: 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: 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: 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: 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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]],
  ['control: 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 5',
   [2,
    [{'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': None, 'z4': 'heat'},
     {'z1': 'cool', 'z4': 'heat'},
     {'z1': None},
     {'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None, 'z4': 'heat'}]],
   [['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z4']],
    ['cool', ['z1']],
    ['cool', ['z1']],
    [None, []],
    ['heat', ['z4']],
    ['heat', ['z1', 'z4']],
    ['cool', ['z2']]]],
  ['regression: scenario 14',
   [2,
    [{'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'heat', 'z3': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': None, 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2']],
    ['heat', ['z2']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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: 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: scenario 11',
   [2,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z3': 'heat'},
     {'z1': None},
     {'z1': None, 'z3': None, 'z4': None},
     {'z1': None, 'z4': None},
     {'z2': None, 'z3': None, 'z4': None},
     {'z2': 'cool', 'z3': None},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': None}]],
   [['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z3']],
    [None, []],
    [None, []],
    [None, []],
    [None, []],
    ['cool', ['z2']],
    ['cool', ['z2']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: 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 13',
   [3,
    [{'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z3': 'heat', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z4': 'cool'}]],
   [['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['cool', ['z1']],
    ['cool', ['z1', 'z4']]]],
  ['regression: scenario 7',
   [5,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': None}]],
   [['cool', ['z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z1', 'z4']],
    ['heat', ['z1']],
    ['heat', ['z1']]]],
  ['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']]]],
  ['control: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['control: 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']]]]]]
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
control: satisfied then opposite[['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]][['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]Passed
control: first minute call[['cool', ['a']], ['cool', ['a']], [None, []]][['cool', ['a']], ['cool', ['a']], [None, []]]Passed
control: 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
control: 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 / 878b8369caed9c947e51e590e2bce31c75b42490a98b8aafa5a32c367b54de45

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

Case digest / b2568254e06e4363db84df80cb52a406c85d98257586e9973dd8f52ddb206ed4