FA-92381 / HVAC thermostat control / Open access
Stage 2 restarts immediately after dropping out · case 01
The second stage cycles on and off every minute during a deep droop.
ROOT CAUSE
The minimum off-time guard for stage 2 is missing.
THE FAILURE
The minimum off-time guard for stage 2 is missing.
Unsuccessful approach: Letting droop bypass the guard still short-cycles stage 2 when the room is far below setpoint.
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 and temp < setpoint - 5)):
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: 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: 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: 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]]],
['control: scenario 3',
[700,
[653,
657,
660,
661,
657,
663,
657,
661,
660,
665,
673,
677,
673,
677,
676,
681,
681,
679,
685,
677,
676,
676,
679,
681,
674,
677,
677]],
[[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[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: 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: 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: 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]]],
['control: scenario 3',
[700,
[699,
691,
687,
680,
688,
682,
680,
676,
681,
675,
672,
664,
661,
665,
665,
667,
674,
669,
677,
671,
664,
665,
672,
666,
666,
664,
660,
665,
662]],
[[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],
[True, True],
[True, True],
[True, True],
[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 17',
[700,
[683,
681,
687,
683,
687,
689,
688,
685,
684,
679,
672,
678,
683,
691,
683,
682,
688,
687,
692,
697,
692]],
[[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, False],
[True, 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: 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,
[697,
690,
685,
682,
687,
690,
693,
687,
689,
697,
689,
685,
680,
679,
671,
675,
680,
675,
676,
678,
673,
668,
663,
662,
665,
662,
661,
669,
666,
665]],
[[False, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True]]],
['control: scenario 2',
[700,
[658,
664,
670,
678,
675,
681,
682,
675,
677,
682,
682,
680,
676,
669,
672,
669,
672,
671,
663,
665,
663,
664,
663,
656,
655,
653,
661,
666,
665,
657]],
[[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True]]]],
[['regression: 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: 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: 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]]],
['control: scenario 3',
[700, [657, 654, 650, 653, 658, 666, 658, 661, 654, 654, 647, 641, 635, 640, 646]],
[[True, True],
[True, True],
[True, True],
[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: 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: 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: scenario 1',
[700, [690, 685, 681, 689, 689, 687, 693, 701, 709, 709, 706, 703, 698, 694, 697, 699, 700, 702]],
[[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False]]],
['control: scenario 2',
[700,
[696,
698,
700,
696,
691,
693,
688,
684,
676,
671,
667,
669,
667,
673,
679,
684,
683,
689,
681,
689,
683,
689,
695,
700]],
[[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[False, False]]],
['control: scenario 3',
[700,
[653,
653,
648,
651,
657,
659,
654,
661,
654,
662,
659,
656,
662,
659,
651,
658,
662,
655,
662,
655,
660,
659,
663,
669,
665]],
[[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True]]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: stage two cycling | [[True, True], [True, False], [True, True], [True, True], [True, True], [True, True], [True, False], [False, False]] | [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]] | Failed |
| regression: stage two cycling late | [[True, True], [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]] | 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: 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 |
| control: scenario 3 | [[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]] | [[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [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 / 2db29d610d9c655b4dcb412e460729948d47e1dd9e197d9dd23d21c1fbebb4fc
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 or temp <= setpoint - 30:
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: 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: 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: 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]]],
['control: scenario 3',
[700,
[653,
657,
660,
661,
657,
663,
657,
661,
660,
665,
673,
677,
673,
677,
676,
681,
681,
679,
685,
677,
676,
676,
679,
681,
674,
677,
677]],
[[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[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: 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: 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: 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]]],
['control: scenario 3',
[700,
[699,
691,
687,
680,
688,
682,
680,
676,
681,
675,
672,
664,
661,
665,
665,
667,
674,
669,
677,
671,
664,
665,
672,
666,
666,
664,
660,
665,
662]],
[[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],
[True, True],
[True, True],
[True, True],
[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 17',
[700,
[683,
681,
687,
683,
687,
689,
688,
685,
684,
679,
672,
678,
683,
691,
683,
682,
688,
687,
692,
697,
692]],
[[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, False],
[True, 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: 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,
[697,
690,
685,
682,
687,
690,
693,
687,
689,
697,
689,
685,
680,
679,
671,
675,
680,
675,
676,
678,
673,
668,
663,
662,
665,
662,
661,
669,
666,
665]],
[[False, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True]]],
['control: scenario 2',
[700,
[658,
664,
670,
678,
675,
681,
682,
675,
677,
682,
682,
680,
676,
669,
672,
669,
672,
671,
663,
665,
663,
664,
663,
656,
655,
653,
661,
666,
665,
657]],
[[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True]]]],
[['regression: 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: 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: 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]]],
['control: scenario 3',
[700, [657, 654, 650, 653, 658, 666, 658, 661, 654, 654, 647, 641, 635, 640, 646]],
[[True, True],
[True, True],
[True, True],
[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: 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: 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: scenario 1',
[700, [690, 685, 681, 689, 689, 687, 693, 701, 709, 709, 706, 703, 698, 694, 697, 699, 700, 702]],
[[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False]]],
['control: scenario 2',
[700,
[696,
698,
700,
696,
691,
693,
688,
684,
676,
671,
667,
669,
667,
673,
679,
684,
683,
689,
681,
689,
683,
689,
695,
700]],
[[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[False, False],
[True, False],
[True, False],
[True, False],
[True, False],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[False, False]]],
['control: scenario 3',
[700,
[653,
653,
648,
651,
657,
659,
654,
661,
654,
662,
659,
656,
662,
659,
651,
658,
662,
655,
662,
655,
660,
659,
663,
669,
665]],
[[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True],
[True, True]]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: stage two cycling | [[True, True], [True, False], [True, True], [True, True], [True, True], [True, True], [True, False], [False, False]] | [[True, True], [True, False], [True, False], [True, False], [True, True], [True, True], [True, False], [False, False]] | Failed |
| regression: stage two cycling late | [[True, True], [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]] | 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: 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 |
| control: scenario 3 | [[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True]] | [[True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [True, True], [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 / cbae724caaee922c4f2ce935d1b9d10218da78be5f556d972aee122c829ae73f
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.166493+00:00.
Case digest / d87ccdf79e107c2c030d8e8b6fc7509b139c474677595290daa49b6eb63cf020