FA-92836 / HVAC thermostat control / Open access
Zone dampers open for zones calling the opposite mode · case 01
A zone calling for heat receives cooled air while the system is cooling.
ROOT CAUSE
Open zones include all calling zones.
THE FAILURE
Open zones include all calling zones.
Unsuccessful approach: Opening every zone in the system is worse still.
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, sorted(heat + cool) if mode else []])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['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']]]],
['control: 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: 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: 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: 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',
[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: 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: 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: first minute call',
[3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
[['cool', ['a']], ['cool', ['a']], [None, []]]],
['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: 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: 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',
[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: 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: first minute call',
[3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
[['cool', ['a']], ['cool', ['a']], [None, []]]],
['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 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 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']]]],
['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']]]],
['control: first minute call',
[3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
[['cool', ['a']], ['cool', ['a']], [None, []]]],
['regression: scenario 3',
[2,
[{'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': 'cool'},
{'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
{'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
{'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
{'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
{'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
{'z1': 'cool', 'z3': 'heat', 'z4': 'cool'}]],
[['cool', ['z2', 'z3', 'z4']],
['cool', ['z1', 'z2', 'z3', 'z4']],
['cool', ['z1', 'z2', 'z3', 'z4']],
['cool', ['z1', 'z2', 'z3', 'z4']],
['cool', ['z2', 'z3', 'z4']],
['heat', ['z3']],
['heat', ['z3']],
['cool', ['z1', 'z2', 'z4']],
['cool', ['z1', 'z4']],
['heat', ['z3']]]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: majority then forced switch | [['cool', ['a', 'b', 'c']], ['cool', ['a', 'b']], ['cool', ['a', 'b']], ['heat', ['a', 'b']], ['heat', ['a']], [None, []]] | [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]] | Failed |
| regression: tie goes to heat | [['heat', ['a', 'b']], ['heat', ['a', 'b']], ['cool', ['b']]] | [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]] | Failed |
| regression: ping pong guard | [['heat', ['a', 'b']], ['heat', ['a', 'b']], ['cool', ['a', 'b']], ['cool', ['a', 'b']], ['heat', ['a', 'b']], ['heat', ['a', 'b']], ['cool', ['a', 'b']]] | [['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']]] | Failed |
| regression: satisfied then opposite | [['cool', ['a']], ['cool', ['a', 'b']], ['heat', ['b']], ['heat', ['b']]] | [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]] | Failed |
| control: first minute call | [['cool', ['a']], ['cool', ['a']], [None, []]] | [['cool', ['a']], ['cool', ['a']], [None, []]] | Passed |
| regression: scenario 1 | [['cool', ['z1']], ['cool', ['z1', 'z2', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['heat', ['z1', 'z2', 'z3', 'z4']], ['heat', ['z1', 'z2', 'z4']], ['heat', ['z1', 'z2', 'z4']], ['heat', ['z2', 'z4']], ['heat', ['z2', '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']]] | Failed |
| regression: scenario 2 | [['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z3']], ['heat', ['z1', 'z3']], ['heat', ['z1', 'z3']], ['heat', ['z1', '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 | [['cool', ['z1', 'z2', 'z3']], ['cool', ['z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['heat', ['z1', 'z2', 'z3']], ['heat', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z3']], ['heat', ['z1', 'z3']], ['heat', ['z1', 'z3']], ['cool', ['z1', 'z3']]] | [['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 / bcabdcc4337c4d70f29c4af350b1315c986e60497ec600990ce243f3d8da1190
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 len(heat) >= len(cool) else 'cool'
since = minute
out.append([mode, sorted(calls) if mode else []])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['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']]]],
['control: 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: 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: 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: 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',
[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: 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: 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: first minute call',
[3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
[['cool', ['a']], ['cool', ['a']], [None, []]]],
['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: 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: 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',
[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: 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: first minute call',
[3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
[['cool', ['a']], ['cool', ['a']], [None, []]]],
['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 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 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']]]],
['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']]]],
['control: first minute call',
[3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
[['cool', ['a']], ['cool', ['a']], [None, []]]],
['regression: scenario 3',
[2,
[{'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': 'cool'},
{'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
{'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
{'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
{'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
{'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
{'z1': 'cool', 'z3': 'heat', 'z4': 'cool'}]],
[['cool', ['z2', 'z3', 'z4']],
['cool', ['z1', 'z2', 'z3', 'z4']],
['cool', ['z1', 'z2', 'z3', 'z4']],
['cool', ['z1', 'z2', 'z3', 'z4']],
['cool', ['z2', 'z3', 'z4']],
['heat', ['z3']],
['heat', ['z3']],
['cool', ['z1', 'z2', 'z4']],
['cool', ['z1', 'z4']],
['heat', ['z3']]]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: majority then forced switch | [['cool', ['a', 'b', 'c']], ['cool', ['a', 'b']], ['cool', ['a', 'b']], ['heat', ['a', 'b']], ['heat', ['a']], [None, []]] | [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]] | Failed |
| regression: tie goes to heat | [['heat', ['a', 'b']], ['heat', ['a', 'b']], ['cool', ['b']]] | [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]] | Failed |
| regression: ping pong guard | [['heat', ['a', 'b']], ['heat', ['a', 'b']], ['cool', ['a', 'b']], ['cool', ['a', 'b']], ['heat', ['a', 'b']], ['heat', ['a', 'b']], ['cool', ['a', 'b']]] | [['heat', ['a']], ['heat', ['a']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], ['cool', ['b']]] | Failed |
| regression: satisfied then opposite | [['cool', ['a']], ['cool', ['a', 'b']], ['heat', ['b']], ['heat', ['b']]] | [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]] | Failed |
| control: first minute call | [['cool', ['a']], ['cool', ['a']], [None, []]] | [['cool', ['a']], ['cool', ['a']], [None, []]] | Passed |
| regression: scenario 1 | [['cool', ['z1', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['heat', ['z1', 'z2', 'z3', 'z4']], ['heat', ['z1', 'z2', 'z4']], ['heat', ['z1', 'z2', 'z3', 'z4']], ['heat', ['z2', 'z4']], ['heat', ['z1', 'z2', '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']]] | Failed |
| regression: scenario 2 | [['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z2', 'z3']], ['heat', ['z1', 'z3', 'z4']], ['heat', ['z1', 'z2', 'z3']], ['heat', ['z1', 'z2', 'z3']], ['heat', ['z1']], ['heat', ['z1', 'z2', 'z4']], ['heat', ['z1', 'z4']], ['heat', ['z1', 'z2', 'z4']], ['heat', ['z1', 'z3', 'z4']]] | [['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 | [['cool', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z2', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['heat', ['z1', 'z2', 'z3']], ['heat', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z2', 'z3', 'z4']], ['cool', ['z1', 'z3', 'z4']], ['heat', ['z1', 'z3', 'z4']], ['heat', ['z1', 'z2', 'z3']], ['cool', ['z1', 'z3']]] | [['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 / 67003817c819a44afb58db7d9dc2bfe1eb529003c5fa052fc8ab6c0f1c283d60
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 8 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗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.743424+00:00.
Case digest / 84afd7b8791023390bd46ccb92cccae93cd4c823f4f292db44aaf6a42ced6398