FAILURE MAP
← Case archive

FA-92376 / HVAC thermostat control / Open access

Stage 2 stays on until the heating setpoint is reached · case 01

High fire runs all the way to setpoint and the room overshoots on every recovery.

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

ROOT CAUSE

The stage-2 end test uses setpoint instead of setpoint - 0.3 F.

THE FAILURE

The stage-2 end test uses setpoint instead of setpoint - 0.3 F.

Unsuccessful approach: Using a strict comparison keeps stage 2 on for one extra sample at the threshold.

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
            run1 = 0
        if s1:
            run1 += 1
        if s2 and (temp >= setpoint 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: 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]]],
  ['regression: scenario 7',
   [700,
    [680,
     679,
     676,
     682,
     683,
     680,
     688,
     686,
     692,
     688,
     692,
     697,
     696,
     688,
     693,
     697,
     702,
     696,
     703,
     699,
     706,
     703,
     703,
     696]],
   [[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, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, 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]]],
  ['control: 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]]],
  ['regression: 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: 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]]],
  ['regression: scenario 36',
   [700,
    [661,
     668,
     666,
     671,
     674,
     671,
     678,
     679,
     687,
     691,
     697,
     692,
     693,
     692,
     687,
     684,
     688,
     688,
     689,
     697,
     694,
     689,
     681,
     686,
     678,
     683,
     685,
     686,
     689]],
   [[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],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [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: 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]]],
  ['regression: 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: 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 5',
   [700,
    [686,
     687,
     692,
     699,
     698,
     690,
     685,
     690,
     684,
     690,
     689,
     686,
     692,
     696,
     695,
     693,
     699,
     703,
     705,
     710,
     708]],
   [[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],
    [False, False]]],
  ['regression: scenario 18',
   [700,
    [665,
     658,
     660,
     666,
     672,
     679,
     685,
     679,
     687,
     689,
     695,
     693,
     685,
     690,
     698,
     694,
     697,
     690,
     691,
     690,
     697,
     701,
     702,
     700]],
   [[True, True],
    [True, True],
    [True, 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],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, 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]]],
  ['control: 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]]],
  ['regression: 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]]],
  ['regression: 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]]]],
 [['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]]],
  ['control: 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]]],
  ['regression: 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]]],
  ['regression: 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]]],
  ['regression: 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: scenario 53',
   [700,
    [679,
     683,
     681,
     682,
     687,
     684,
     677,
     674,
     681,
     673,
     666,
     670,
     671,
     670,
     665,
     657,
     665,
     671,
     677,
     683,
     690,
     691,
     697]],
   [[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, False]]],
  ['regression: scenario 46',
   [700,
    [674,
     678,
     684,
     683,
     687,
     691,
     685,
     683,
     683,
     676,
     672,
     677,
     676,
     682,
     690,
     697,
     689,
     693,
     696,
     703,
     698,
     698,
     698,
     703,
     697,
     697,
     691,
     688,
     691]],
   [[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, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, 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]]],
  ['control: 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]]],
  ['regression: 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]]],
  ['regression: 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]]]]]
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: stage two cycling[[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [False, False]][[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]]Failed
regression: scenario 7[[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], [False, 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], [True, False], [True, True], [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]]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: 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
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
regression: stage two cycling late[[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], [True, True]]Failed
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 / cb5795736a49b156d4ce9b1e35bc140fc5c90242d17c642a19befcdb6d1bd2f7

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 = 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: 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]]],
  ['regression: scenario 7',
   [700,
    [680,
     679,
     676,
     682,
     683,
     680,
     688,
     686,
     692,
     688,
     692,
     697,
     696,
     688,
     693,
     697,
     702,
     696,
     703,
     699,
     706,
     703,
     703,
     696]],
   [[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, True],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, 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]]],
  ['control: 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]]],
  ['regression: 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: 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]]],
  ['regression: scenario 36',
   [700,
    [661,
     668,
     666,
     671,
     674,
     671,
     678,
     679,
     687,
     691,
     697,
     692,
     693,
     692,
     687,
     684,
     688,
     688,
     689,
     697,
     694,
     689,
     681,
     686,
     678,
     683,
     685,
     686,
     689]],
   [[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],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [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: 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]]],
  ['regression: 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: 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 5',
   [700,
    [686,
     687,
     692,
     699,
     698,
     690,
     685,
     690,
     684,
     690,
     689,
     686,
     692,
     696,
     695,
     693,
     699,
     703,
     705,
     710,
     708]],
   [[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],
    [False, False]]],
  ['regression: scenario 18',
   [700,
    [665,
     658,
     660,
     666,
     672,
     679,
     685,
     679,
     687,
     689,
     695,
     693,
     685,
     690,
     698,
     694,
     697,
     690,
     691,
     690,
     697,
     701,
     702,
     700]],
   [[True, True],
    [True, True],
    [True, 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],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [False, False],
    [False, False],
    [False, 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]]],
  ['control: 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]]],
  ['regression: 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]]],
  ['regression: 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]]]],
 [['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]]],
  ['control: 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]]],
  ['regression: 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]]],
  ['regression: 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]]],
  ['regression: 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: scenario 53',
   [700,
    [679,
     683,
     681,
     682,
     687,
     684,
     677,
     674,
     681,
     673,
     666,
     670,
     671,
     670,
     665,
     657,
     665,
     671,
     677,
     683,
     690,
     691,
     697]],
   [[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, False]]],
  ['regression: scenario 46',
   [700,
    [674,
     678,
     684,
     683,
     687,
     691,
     685,
     683,
     683,
     676,
     672,
     677,
     676,
     682,
     690,
     697,
     689,
     693,
     696,
     703,
     698,
     698,
     698,
     703,
     697,
     697,
     691,
     688,
     691]],
   [[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, False],
    [True, False],
    [True, False],
    [True, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, 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]]],
  ['control: 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]]],
  ['regression: 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]]],
  ['regression: 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]]]]]
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: 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
regression: scenario 7[[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], [False, 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], [True, False], [True, True], [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]]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: 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
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
regression: 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 / ad3297915f3b900717926cd175c39e61c909923db018cbadc6e41756d2fd422e

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

Case digest / dd002d99ae12a95976381bf2d6d2da90558c0ddbea7e7eb490ac8478dea60da1