FAILURE MAP
← Case archive

FA-92366 / HVAC thermostat control / Open access

Stage-2 time upstage counts stage-1 runtime from earlier cycles · case 01

A new heating cycle brings on the second stage almost immediately because previous cycles' runtime is carried over.

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

ROOT CAUSE

The stage-1 runtime counter is not cleared when a new stage-1 call begins.

VERIFIED REPAIR

Restart the stage-1 runtime count at each stage-1 start.

Unsuccessful approach: Capping the carried runtime at five samples still upstages early.

Case contract

Two-stage furnace thermostat sampled per minute. Stage 1 starts at temp <= setpoint - 1.0 F and ends at temp >= setpoint. Stage 2 requires stage 1 and starts either on droop (temp <= setpoint - 3.0 F) or after stage 1 has been on for more than 10 samples of the current cycle while still below setpoint - 0.5 F; it ends at temp >= setpoint - 0.3 F or when stage 1 ends, and cannot restart within 3 minutes of ending. Return [stage1, stage2] 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(setpoint, temps):
    s1 = False
    s2 = False
    run1 = 0
    s2_off = None
    out = []
    for minute, temp in enumerate(temps):
        if s1 and temp >= setpoint:
            s1 = False
        elif not s1 and temp <= setpoint - 10:
            s1 = True
        if s1:
            run1 += 1
        if s2 and (temp >= setpoint - 3 or not s1):
            s2 = False
            s2_off = minute
        elif not s2 and s1 and (temp <= setpoint - 30 or (run1 > 10 and temp < setpoint - 5)):
            if s2_off is None or minute - s2_off >= 3:
                s2 = True
        out.append([s1, s2])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['regression: scenario 42',
   [700,
    [695,
     698,
     695,
     690,
     688,
     682,
     680,
     676,
     683,
     685,
     687,
     694,
     695,
     700,
     700,
     700,
     692,
     687,
     682,
     681,
     677,
     674,
     678,
     670,
     668,
     675,
     668]],
   [[False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [668,
     676,
     684,
     689,
     688,
     685,
     691,
     686,
     690,
     688,
     696,
     688,
     691,
     693,
     690,
     693,
     693,
     686,
     679,
     685,
     678,
     682,
     677,
     685,
     679,
     675,
     682,
     688,
     696]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700, [650, 652, 648, 644, 640, 637, 645, 650, 657, 654, 651, 644, 643, 651, 645, 643, 635]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]]],
 [['regression: scenario 27',
   [700,
    [694,
     696,
     689,
     690,
     691,
     688,
     681,
     681,
     678,
     670,
     675,
     674,
     680,
     685,
     682,
     688,
     684,
     690,
     695,
     699,
     691,
     690,
     690,
     696,
     704,
     701,
     695,
     690,
     698]],
   [[False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [664,
     664,
     656,
     661,
     657,
     652,
     647,
     647,
     642,
     647,
     646,
     644,
     642,
     634,
     634,
     637,
     640,
     644,
     650,
     643,
     640,
     640]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700, [678, 683, 689, 697, 705, 705, 710, 705, 704, 709, 701, 709, 710, 710, 704, 696, 702, 705, 709]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]]],
 [['regression: scenario 37',
   [700, [689, 694, 693, 701, 697, 698, 691, 693, 695, 692, 688, 680, 674, 675, 677, 679, 675, 671, 676]],
   [[True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [697,
     690,
     685,
     682,
     687,
     690,
     693,
     687,
     689,
     697,
     689,
     685,
     680,
     679,
     671,
     675,
     680,
     675,
     676,
     678,
     673,
     668,
     663,
     662,
     665,
     662,
     661,
     669,
     666,
     665]],
   [[False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700,
    [658,
     664,
     670,
     678,
     675,
     681,
     682,
     675,
     677,
     682,
     682,
     680,
     676,
     669,
     672,
     669,
     672,
     671,
     663,
     665,
     663,
     664,
     663,
     656,
     655,
     653,
     661,
     666,
     665,
     657]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]]],
 [['regression: scenario 9',
   [700,
    [685,
     682,
     690,
     695,
     703,
     708,
     700,
     692,
     693,
     689,
     684,
     677,
     671,
     677,
     684,
     677,
     676,
     684,
     683,
     682,
     679,
     683,
     687,
     691,
     692,
     699,
     704,
     702,
     708]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False]]],
  ['regression: scenario 39',
   [700,
    [691,
     692,
     691,
     685,
     683,
     676,
     671,
     679,
     684,
     677,
     685,
     693,
     689,
     693,
     694,
     697,
     705,
     697,
     693,
     688,
     690,
     686,
     681,
     686,
     684,
     683]],
   [[False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [682,
     679,
     685,
     683,
     680,
     678,
     684,
     682,
     681,
     688,
     693,
     698,
     702,
     710,
     710,
     710,
     708,
     701,
     694,
     696,
     693]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]]],
 [['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['regression: scenario 12',
   [700,
    [677,
     675,
     680,
     674,
     677,
     682,
     688,
     683,
     683,
     691,
     696,
     700,
     703,
     696,
     697,
     696,
     692,
     690,
     686,
     678,
     682,
     686,
     689,
     685,
     677,
     672,
     668,
     671,
     674]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700, [690, 685, 681, 689, 689, 687, 693, 701, 709, 709, 706, 703, 698, 694, 697, 699, 700, 702]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]],
  ['control: scenario 2',
   [700,
    [696,
     698,
     700,
     696,
     691,
     693,
     688,
     684,
     676,
     671,
     667,
     669,
     667,
     673,
     679,
     684,
     683,
     689,
     681,
     689,
     683,
     689,
     695,
     700]],
   [[False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: second cycle after short first[[True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True]]Failed
regression: scenario 42[[False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [False, False], [False, False], [False, False], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True]]Failed
control: slow recovery upstages on time[[True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [False, False]][[True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [False, False]]Passed
control: droop recovery above upstage exit[[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]][[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]Passed
control: stage two cycling[[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]][[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]]Passed
control: stage two cycling late[[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]][[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]Passed
control: scenario 1[[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]]Passed
control: scenario 2[[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]]Passed

SHA-256 / f0b84276f41b806265f96b5768d4f874f091621c25b0c173dd0d10353b756a97

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(setpoint, temps):
    s1 = False
    s2 = False
    run1 = 0
    s2_off = None
    out = []
    for minute, temp in enumerate(temps):
        if s1 and temp >= setpoint:
            s1 = False
        elif not s1 and temp <= setpoint - 10:
            s1 = True
            run1 = min(run1, 5)
        if s1:
            run1 += 1
        if s2 and (temp >= setpoint - 3 or not s1):
            s2 = False
            s2_off = minute
        elif not s2 and s1 and (temp <= setpoint - 30 or (run1 > 10 and temp < setpoint - 5)):
            if s2_off is None or minute - s2_off >= 3:
                s2 = True
        out.append([s1, s2])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['regression: scenario 42',
   [700,
    [695,
     698,
     695,
     690,
     688,
     682,
     680,
     676,
     683,
     685,
     687,
     694,
     695,
     700,
     700,
     700,
     692,
     687,
     682,
     681,
     677,
     674,
     678,
     670,
     668,
     675,
     668]],
   [[False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [668,
     676,
     684,
     689,
     688,
     685,
     691,
     686,
     690,
     688,
     696,
     688,
     691,
     693,
     690,
     693,
     693,
     686,
     679,
     685,
     678,
     682,
     677,
     685,
     679,
     675,
     682,
     688,
     696]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700, [650, 652, 648, 644, 640, 637, 645, 650, 657, 654, 651, 644, 643, 651, 645, 643, 635]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]]],
 [['regression: scenario 27',
   [700,
    [694,
     696,
     689,
     690,
     691,
     688,
     681,
     681,
     678,
     670,
     675,
     674,
     680,
     685,
     682,
     688,
     684,
     690,
     695,
     699,
     691,
     690,
     690,
     696,
     704,
     701,
     695,
     690,
     698]],
   [[False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [664,
     664,
     656,
     661,
     657,
     652,
     647,
     647,
     642,
     647,
     646,
     644,
     642,
     634,
     634,
     637,
     640,
     644,
     650,
     643,
     640,
     640]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700, [678, 683, 689, 697, 705, 705, 710, 705, 704, 709, 701, 709, 710, 710, 704, 696, 702, 705, 709]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]]],
 [['regression: scenario 37',
   [700, [689, 694, 693, 701, 697, 698, 691, 693, 695, 692, 688, 680, 674, 675, 677, 679, 675, 671, 676]],
   [[True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [697,
     690,
     685,
     682,
     687,
     690,
     693,
     687,
     689,
     697,
     689,
     685,
     680,
     679,
     671,
     675,
     680,
     675,
     676,
     678,
     673,
     668,
     663,
     662,
     665,
     662,
     661,
     669,
     666,
     665]],
   [[False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700,
    [658,
     664,
     670,
     678,
     675,
     681,
     682,
     675,
     677,
     682,
     682,
     680,
     676,
     669,
     672,
     669,
     672,
     671,
     663,
     665,
     663,
     664,
     663,
     656,
     655,
     653,
     661,
     666,
     665,
     657]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]]],
 [['regression: scenario 9',
   [700,
    [685,
     682,
     690,
     695,
     703,
     708,
     700,
     692,
     693,
     689,
     684,
     677,
     671,
     677,
     684,
     677,
     676,
     684,
     683,
     682,
     679,
     683,
     687,
     691,
     692,
     699,
     704,
     702,
     708]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False]]],
  ['regression: scenario 39',
   [700,
    [691,
     692,
     691,
     685,
     683,
     676,
     671,
     679,
     684,
     677,
     685,
     693,
     689,
     693,
     694,
     697,
     705,
     697,
     693,
     688,
     690,
     686,
     681,
     686,
     684,
     683]],
   [[False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [682,
     679,
     685,
     683,
     680,
     678,
     684,
     682,
     681,
     688,
     693,
     698,
     702,
     710,
     710,
     710,
     708,
     701,
     694,
     696,
     693]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]]],
 [['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['regression: scenario 12',
   [700,
    [677,
     675,
     680,
     674,
     677,
     682,
     688,
     683,
     683,
     691,
     696,
     700,
     703,
     696,
     697,
     696,
     692,
     690,
     686,
     678,
     682,
     686,
     689,
     685,
     677,
     672,
     668,
     671,
     674]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700, [690, 685, 681, 689, 689, 687, 693, 701, 709, 709, 706, 703, 698, 694, 697, 699, 700, 702]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]],
  ['control: scenario 2',
   [700,
    [696,
     698,
     700,
     696,
     691,
     693,
     688,
     684,
     676,
     671,
     667,
     669,
     667,
     673,
     679,
     684,
     683,
     689,
     681,
     689,
     683,
     689,
     695,
     700]],
   [[False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: second cycle after short first[[True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True]]Failed
regression: scenario 42[[False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [True, True]][[False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True]]Failed
control: slow recovery upstages on time[[True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [False, False]][[True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [False, False]]Passed
control: droop recovery above upstage exit[[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]][[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]Passed
control: stage two cycling[[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]][[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]]Passed
control: stage two cycling late[[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]][[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]Passed
control: scenario 1[[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]]Passed
control: scenario 2[[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]]Passed

SHA-256 / 383efbec90c115fd0944c0eba696d615488af3b4ec3688ddb189540d6eaa0313

3 / The verified repair

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

N = 1
observations = []
def solve(setpoint, temps):
    s1 = False
    s2 = False
    run1 = 0
    s2_off = None
    out = []
    for minute, temp in enumerate(temps):
        if s1 and temp >= setpoint:
            s1 = False
        elif not s1 and temp <= setpoint - 10:
            s1 = True
            run1 = 0
        if s1:
            run1 += 1
        if s2 and (temp >= setpoint - 3 or not s1):
            s2 = False
            s2_off = minute
        elif not s2 and s1 and (temp <= setpoint - 30 or (run1 > 10 and temp < setpoint - 5)):
            if s2_off is None or minute - s2_off >= 3:
                s2 = True
        out.append([s1, s2])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['regression: scenario 42',
   [700,
    [695,
     698,
     695,
     690,
     688,
     682,
     680,
     676,
     683,
     685,
     687,
     694,
     695,
     700,
     700,
     700,
     692,
     687,
     682,
     681,
     677,
     674,
     678,
     670,
     668,
     675,
     668]],
   [[False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [668,
     676,
     684,
     689,
     688,
     685,
     691,
     686,
     690,
     688,
     696,
     688,
     691,
     693,
     690,
     693,
     693,
     686,
     679,
     685,
     678,
     682,
     677,
     685,
     679,
     675,
     682,
     688,
     696]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700, [650, 652, 648, 644, 640, 637, 645, 650, 657, 654, 651, 644, 643, 651, 645, 643, 635]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]]],
 [['regression: scenario 27',
   [700,
    [694,
     696,
     689,
     690,
     691,
     688,
     681,
     681,
     678,
     670,
     675,
     674,
     680,
     685,
     682,
     688,
     684,
     690,
     695,
     699,
     691,
     690,
     690,
     696,
     704,
     701,
     695,
     690,
     698]],
   [[False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [664,
     664,
     656,
     661,
     657,
     652,
     647,
     647,
     642,
     647,
     646,
     644,
     642,
     634,
     634,
     637,
     640,
     644,
     650,
     643,
     640,
     640]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700, [678, 683, 689, 697, 705, 705, 710, 705, 704, 709, 701, 709, 710, 710, 704, 696, 702, 705, 709]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]]],
 [['regression: scenario 37',
   [700, [689, 694, 693, 701, 697, 698, 691, 693, 695, 692, 688, 680, 674, 675, 677, 679, 675, 671, 676]],
   [[True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [697,
     690,
     685,
     682,
     687,
     690,
     693,
     687,
     689,
     697,
     689,
     685,
     680,
     679,
     671,
     675,
     680,
     675,
     676,
     678,
     673,
     668,
     663,
     662,
     665,
     662,
     661,
     669,
     666,
     665]],
   [[False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: scenario 2',
   [700,
    [658,
     664,
     670,
     678,
     675,
     681,
     682,
     675,
     677,
     682,
     682,
     680,
     676,
     669,
     672,
     669,
     672,
     671,
     663,
     665,
     663,
     664,
     663,
     656,
     655,
     653,
     661,
     666,
     665,
     657]],
   [[True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True]]]],
 [['regression: scenario 9',
   [700,
    [685,
     682,
     690,
     695,
     703,
     708,
     700,
     692,
     693,
     689,
     684,
     677,
     671,
     677,
     684,
     677,
     676,
     684,
     683,
     682,
     679,
     683,
     687,
     691,
     692,
     699,
     704,
     702,
     708]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False]]],
  ['regression: scenario 39',
   [700,
    [691,
     692,
     691,
     685,
     683,
     676,
     671,
     679,
     684,
     677,
     685,
     693,
     689,
     693,
     694,
     697,
     705,
     697,
     693,
     688,
     690,
     686,
     681,
     686,
     684,
     683]],
   [[False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700,
    [682,
     679,
     685,
     683,
     680,
     678,
     684,
     682,
     681,
     688,
     693,
     698,
     702,
     710,
     710,
     710,
     708,
     701,
     694,
     696,
     693]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]]],
 [['regression: second cycle after short first',
   [700, [690, 692, 694, 696, 698, 700, 690, 692, 694, 694, 694, 694, 694, 694, 694, 694, 694]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True]]],
  ['regression: scenario 12',
   [700,
    [677,
     675,
     680,
     674,
     677,
     682,
     688,
     683,
     683,
     691,
     696,
     700,
     703,
     696,
     697,
     696,
     692,
     690,
     686,
     678,
     682,
     686,
     689,
     685,
     677,
     672,
     668,
     671,
     674]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True]]],
  ['control: slow recovery upstages on time',
   [700, [690, 691, 692, 692, 693, 693, 694, 694, 694, 694, 694, 694, 695, 696, 700]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]],
  ['control: droop recovery above upstage exit',
   [700, [665, 675, 685, 693, 696, 700]],
   [[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]],
  ['control: stage two cycling',
   [700, [665, 698, 668, 668, 668, 668, 699, 700]],
   [[True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, False],
    [False, False]]],
  ['control: stage two cycling late',
   [700, [669, 698, 669, 669, 666, 669, 669]],
   [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]],
  ['control: scenario 1',
   [700, [690, 685, 681, 689, 689, 687, 693, 701, 709, 709, 706, 703, 698, 694, 697, 699, 700, 702]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]],
  ['control: scenario 2',
   [700,
    [696,
     698,
     700,
     696,
     691,
     693,
     688,
     684,
     676,
     671,
     667,
     669,
     667,
     673,
     679,
     684,
     683,
     689,
     681,
     689,
     683,
     689,
     695,
     700]],
   [[False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [False, False]]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: second cycle after short first[[True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True]][[True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True]]Passed
regression: scenario 42[[False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True]][[False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [False, False], [False, False], [False, False], [False, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True]]Passed
control: slow recovery upstages on time[[True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [False, False]][[True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [False, False]]Passed
control: droop recovery above upstage exit[[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]][[True, True], [True, True], [True, True], [True, True], [True, True], [False, False]]Passed
control: stage two cycling[[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]][[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]]Passed
control: stage two cycling late[[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]][[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True]]Passed
control: scenario 1[[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]]Passed
control: scenario 2[[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]][[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]]Passed

SHA-256 / 8566d9a6af1876d595f40a2175970795968b89ecae2ffb86c5d50ce3b624e82c

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

Case digest / 6a7b4316e5eb6bec6765b0599ffbbcbfabccd8f284ed7d1f30d8641bde22adba