FAILURE MAP
← Case archive

FA-92371 / HVAC thermostat control / Open access

Stage-2 time upstage ignores how close the room is to setpoint · case 01

The second stage kicks in after ten minutes even when the room is within a few tenths of setpoint, overshooting.

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

ROOT CAUSE

The time-based upstage condition omits the temperature qualifier.

THE FAILURE

The time-based upstage condition omits the temperature qualifier.

Unsuccessful approach: Qualifying with temp < setpoint still upstages within the last half degree.

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 - 3 or not s1):
            s2 = False
            s2_off = minute
        elif not s2 and s1 and (temp <= setpoint - 30 or (run1 > 10)):
            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: scenario 27',
   [700,
    [678,
     676,
     674,
     680,
     681,
     673,
     681,
     680,
     680,
     684,
     689,
     693,
     699,
     693,
     695,
     698,
     690,
     695,
     688,
     693,
     698,
     690,
     698,
     703]],
   [[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],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [True, False],
    [True, False],
    [False, False]]],
  ['regression: scenario 36',
   [700, [681, 681, 689, 682, 678, 685, 693, 687, 691, 695, 695, 694, 702, 707, 701, 707]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [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]]],
  ['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]]]],
 [['regression: scenario 34',
   [700, [690, 690, 690, 688, 693, 697, 698, 694, 696, 688, 695, 691, 687, 687, 684, 678, 674, 680, 680]],
   [[True, 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]]],
  ['regression: scenario 39',
   [700, [677, 677, 684, 690, 693, 687, 689, 689, 691, 694, 695, 701, 709, 710, 704, 709, 708, 706]],
   [[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],
    [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]]],
  ['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]]]],
 [['regression: scenario 29',
   [700, [694, 696, 695, 690, 689, 697, 697, 689, 687, 688, 692, 696, 694, 697, 703]],
   [[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, False],
    [False, False]]],
  ['regression: scenario 48',
   [700,
    [698,
     693,
     699,
     698,
     690,
     698,
     699,
     695,
     688,
     689,
     681,
     681,
     689,
     688,
     696,
     702,
     710,
     710,
     710,
     710,
     710,
     710,
     703,
     705,
     705,
     702,
     702,
     710,
     706,
     698]],
   [[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, 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]]],
  ['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]]],
  ['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]]]],
 [['regression: scenario 58',
   [700,
    [692,
     687,
     679,
     674,
     681,
     675,
     679,
     687,
     692,
     694,
     690,
     696,
     695,
     700,
     695,
     692,
     691,
     687,
     687,
     682,
     686,
     680,
     685,
     692,
     690]],
   [[False, False],
    [True, False],
    [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],
    [True, 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]]],
  ['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]]],
  ['control: scenario 2',
   [700,
    [665,
     665,
     663,
     660,
     657,
     651,
     650,
     644,
     639,
     643,
     637,
     635,
     628,
     628,
     636,
     634,
     634,
     638,
     645,
     647,
     654,
     655,
     659,
     660,
     657,
     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]]]],
 [['regression: scenario 13',
   [700,
    [686,
     678,
     680,
     680,
     686,
     686,
     692,
     695,
     697,
     696,
     699,
     697,
     704,
     710,
     706,
     709,
     707,
     709,
     702,
     707,
     707,
     709,
     710,
     710,
     703,
     702,
     702]],
   [[True, False],
    [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],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]],
  ['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: 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, [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: scenario 27[[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], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [True, True], [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, True], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [True, False], [True, False], [True, False], [False, False]]Failed
regression: scenario 36[[True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [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, False], [True, True], [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
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

SHA-256 / bcf04204496d598a0baaf1be56252150f9dd1ce469f573ed485efbd5213d2054

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)):
            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: scenario 27',
   [700,
    [678,
     676,
     674,
     680,
     681,
     673,
     681,
     680,
     680,
     684,
     689,
     693,
     699,
     693,
     695,
     698,
     690,
     695,
     688,
     693,
     698,
     690,
     698,
     703]],
   [[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],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [True, True],
    [True, True],
    [True, True],
    [True, False],
    [True, False],
    [True, False],
    [False, False]]],
  ['regression: scenario 36',
   [700, [681, 681, 689, 682, 678, 685, 693, 687, 691, 695, 695, 694, 702, 707, 701, 707]],
   [[True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, False],
    [True, True],
    [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]]],
  ['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]]]],
 [['regression: scenario 34',
   [700, [690, 690, 690, 688, 693, 697, 698, 694, 696, 688, 695, 691, 687, 687, 684, 678, 674, 680, 680]],
   [[True, 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]]],
  ['regression: scenario 39',
   [700, [677, 677, 684, 690, 693, 687, 689, 689, 691, 694, 695, 701, 709, 710, 704, 709, 708, 706]],
   [[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],
    [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]]],
  ['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]]]],
 [['regression: scenario 29',
   [700, [694, 696, 695, 690, 689, 697, 697, 689, 687, 688, 692, 696, 694, 697, 703]],
   [[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, False],
    [False, False]]],
  ['regression: scenario 48',
   [700,
    [698,
     693,
     699,
     698,
     690,
     698,
     699,
     695,
     688,
     689,
     681,
     681,
     689,
     688,
     696,
     702,
     710,
     710,
     710,
     710,
     710,
     710,
     703,
     705,
     705,
     702,
     702,
     710,
     706,
     698]],
   [[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, 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]]],
  ['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]]],
  ['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]]]],
 [['regression: scenario 58',
   [700,
    [692,
     687,
     679,
     674,
     681,
     675,
     679,
     687,
     692,
     694,
     690,
     696,
     695,
     700,
     695,
     692,
     691,
     687,
     687,
     682,
     686,
     680,
     685,
     692,
     690]],
   [[False, False],
    [True, False],
    [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],
    [True, 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]]],
  ['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]]],
  ['control: scenario 2',
   [700,
    [665,
     665,
     663,
     660,
     657,
     651,
     650,
     644,
     639,
     643,
     637,
     635,
     628,
     628,
     636,
     634,
     634,
     638,
     645,
     647,
     654,
     655,
     659,
     660,
     657,
     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]]]],
 [['regression: scenario 13',
   [700,
    [686,
     678,
     680,
     680,
     686,
     686,
     692,
     695,
     697,
     696,
     699,
     697,
     704,
     710,
     706,
     709,
     707,
     709,
     702,
     707,
     707,
     709,
     710,
     710,
     703,
     702,
     702]],
   [[True, False],
    [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],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False],
    [False, False]]],
  ['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: 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, [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: scenario 27[[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], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [True, True], [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, True], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [True, True], [True, True], [True, False], [True, False], [True, False], [False, False]]Failed
regression: scenario 36[[True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, False], [True, True], [True, True], [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, False], [True, True], [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
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

SHA-256 / 36592134f90e6e4d4dc68f6b6e99c74bc80a718492f23fbed9480553a2f89a70

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

Case digest / 097398175b0c4839554e670e1b2e05aebbe437c18502353b092ca803bb93f6f4