{"abstract":"Rooms never reach the heating setpoint and the call chatters at the bottom of the band.","category":"HVAC thermostat control","checks":8,"contract":"Auto heat/cool thermostat sampled once per minute (temps in tenths F). If the cooling setpoint is less than 3.0 F above the heating setpoint it is pushed up to heat_sp + 30 (the heating setpoint wins). Heating starts below heat_sp - 1.0 F and ends at temp >= heat_sp; cooling starts above cool_sp + 1.0 F and ends at temp <= cool_sp. After a heating call ends, cooling may not start until 5 minutes later, and vice versa. Return heat, cool or idle per minute.","contract_signature":"heat_sp, cool_sp, temps","evaluation_group":"w2-hvac-thermostat-control-auto-changeover-deadband","failed_approach":"Ending only above setpoint overshoots by one tenth on every cycle.","family":"w2-hvac-thermostat-control-auto-changeover-deadband-heat-end-point","id":"FA-92351","implementations":{"attempt":{"sha256":"764dd9351ca2dab7fcfc59a8d06f3d0fa5a38e30c9812623f5a50dff1101b856","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(heat_sp, cool_sp, temps):\n    diff = 10\n    if cool_sp - heat_sp < 30:\n        cool_sp = heat_sp + 30\n    state = 'idle'\n    last_heat_end = None\n    last_cool_end = None\n    out = []\n    for minute, temp in enumerate(temps):\n        if state == 'heat' and temp > heat_sp:\n            state = 'idle'\n            last_heat_end = minute\n        elif state == 'cool' and temp <= cool_sp:\n            state = 'idle'\n            last_cool_end = minute\n        if state == 'idle':\n            if temp < heat_sp - diff and (last_cool_end is None or minute - last_cool_end >= 5):\n                state = 'heat'\n            elif temp > cool_sp + diff and (last_heat_end is None or minute - last_heat_end >= 5):\n                state = 'cool'\n        out.append(state)\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['regression: scenario 3',\n   [680,\n    740,\n    [649,\n     667,\n     643,\n     622,\n     637,\n     657,\n     634,\n     649,\n     674,\n     654,\n     672,\n     675,\n     698,\n     687,\n     666,\n     654,\n     670,\n     645,\n     654,\n     637,\n     651,\n     672]],\n   ['heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['control: scenario 1',\n   [680, 690, [693, 687, 709, 709, 685, 704, 684, 680, 686, 687, 679]],\n   ['idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: scenario 2',\n   [680, 700, [681, 686, 698, 703, 724, 744, 752, 732, 755, 742, 762, 772]],\n   ['idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool']],\n  ['control: scenario 4',\n   [680, 720, [678, 693, 708, 706, 691, 698, 702, 725, 720, 725, 717, 703, 717, 731, 714, 728, 740, 735]],\n   ['idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'cool',\n    'idle',\n    'idle',\n    'cool',\n    'cool']]],\n [['regression: scenario 6',\n   [680,\n    690,\n    [694, 696, 693, 697, 678, 655, 668, 684, 659, 671, 693, 680, 655, 660, 640, 655, 657, 634, 622, 620]],\n   ['idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'idle',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['regression: scenario 29',\n   [680, 700, [694, 696, 676, 693, 679, 684, 666, 676, 671, 659, 680, 680, 658, 650, 662, 677]],\n   ['idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['control: scenario 1',\n   [680, 700, [687, 695, 710, 721, 712, 724, 736, 738, 737, 740, 748]],\n   ['idle', 'idle', 'idle', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool']],\n  ['control: scenario 2',\n   [680, 710, [674, 681, 688, 699, 718, 698, 716, 709, 691, 672, 678, 701, 724, 699, 683, 698, 691, 701]],\n   ['idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'cool',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle']]],\n [['regression: scenario 10',\n   [680, 700, [693, 681, 656, 676, 697, 710, 694, 681, 682, 707, 717, 711, 736, 731, 735]],\n   ['idle',\n    'idle',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'cool',\n    'cool',\n    'cool']],\n  ['regression: scenario 52',\n   [680, 700, [670, 669, 652, 663, 640, 620, 634, 649, 660, 680]],\n   ['idle', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'idle']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['control: scenario 1',\n   [680, 710, [758, 778, 769, 788, 780, 787, 790, 773, 789, 766, 785, 779, 790, 790, 790, 777, 790]],\n   ['cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool']],\n  ['regression: scenario 2',\n   [680, 740, [646, 654, 672, 672, 692, 717, 736, 759, 769, 790, 790]],\n   ['heat', 'heat', 'heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']]],\n [['regression: scenario 9',\n   [680, 690, [659, 637, 655, 663, 655, 654, 639, 635, 631, 656, 667, 672, 683, 704, 683, 696, 718]],\n   ['heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle']],\n  ['regression: scenario 35',\n   [680,\n    690,\n    [712,\n     690,\n     682,\n     662,\n     680,\n     655,\n     665,\n     643,\n     622,\n     636,\n     657,\n     681,\n     658,\n     663,\n     656,\n     663,\n     649,\n     661,\n     657,\n     643,\n     667]],\n   ['idle',\n    'idle',\n    'idle',\n    'heat',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['regression: scenario 1',\n   [680,\n    690,\n    [671, 646, 636, 635, 620, 625, 635, 653, 659, 636, 645, 633, 620, 628, 620, 638, 653, 655, 666, 678]],\n   ['idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['regression: scenario 2',\n   [680, 740, [655, 638, 663, 641, 622, 636, 628, 621, 621, 620, 635, 632, 644, 651, 656, 675, 687]],\n   ['heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle']]],\n [['regression: scenario 19',\n   [680,\n    690,\n    [644, 668, 674, 684, 659, 674, 661, 653, 633, 642, 656, 675, 656, 679, 675, 677, 700, 714, 720]],\n   ['heat',\n    'heat',\n    'heat',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'idle']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['control: scenario 1',\n   [680, 720, [774, 779, 785, 790, 790, 781, 778, 777, 770, 767, 743, 730, 708, 690]],\n   ['cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'idle',\n    'idle']],\n  ['control: scenario 2',\n   [680,\n    710,\n    [701,\n     679,\n     702,\n     721,\n     727,\n     748,\n     743,\n     720,\n     741,\n     738,\n     762,\n     769,\n     758,\n     740,\n     744,\n     725,\n     748,\n     728,\n     742,\n     755,\n     769]],\n   ['idle',\n    'idle',\n    'idle',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool']],\n  ['control: scenario 3',\n   [680, 720, [645, 664, 650, 632, 620, 628, 652, 666, 661, 660, 644]],\n   ['heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat']]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"05efc62baa5ff4c86924658e92c95eaa41df8ace2653b21233890fc9cb59d290","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(heat_sp, cool_sp, temps):\n    diff = 10\n    if cool_sp - heat_sp < 30:\n        cool_sp = heat_sp + 30\n    state = 'idle'\n    last_heat_end = None\n    last_cool_end = None\n    out = []\n    for minute, temp in enumerate(temps):\n        if state == 'heat' and temp >= heat_sp - diff:\n            state = 'idle'\n            last_heat_end = minute\n        elif state == 'cool' and temp <= cool_sp:\n            state = 'idle'\n            last_cool_end = minute\n        if state == 'idle':\n            if temp < heat_sp - diff and (last_cool_end is None or minute - last_cool_end >= 5):\n                state = 'heat'\n            elif temp > cool_sp + diff and (last_heat_end is None or minute - last_heat_end >= 5):\n                state = 'cool'\n        out.append(state)\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['regression: scenario 3',\n   [680,\n    740,\n    [649,\n     667,\n     643,\n     622,\n     637,\n     657,\n     634,\n     649,\n     674,\n     654,\n     672,\n     675,\n     698,\n     687,\n     666,\n     654,\n     670,\n     645,\n     654,\n     637,\n     651,\n     672]],\n   ['heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['control: scenario 1',\n   [680, 690, [693, 687, 709, 709, 685, 704, 684, 680, 686, 687, 679]],\n   ['idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: scenario 2',\n   [680, 700, [681, 686, 698, 703, 724, 744, 752, 732, 755, 742, 762, 772]],\n   ['idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool']],\n  ['control: scenario 4',\n   [680, 720, [678, 693, 708, 706, 691, 698, 702, 725, 720, 725, 717, 703, 717, 731, 714, 728, 740, 735]],\n   ['idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'cool',\n    'idle',\n    'idle',\n    'cool',\n    'cool']]],\n [['regression: scenario 6',\n   [680,\n    690,\n    [694, 696, 693, 697, 678, 655, 668, 684, 659, 671, 693, 680, 655, 660, 640, 655, 657, 634, 622, 620]],\n   ['idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'idle',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['regression: scenario 29',\n   [680, 700, [694, 696, 676, 693, 679, 684, 666, 676, 671, 659, 680, 680, 658, 650, 662, 677]],\n   ['idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['control: scenario 1',\n   [680, 700, [687, 695, 710, 721, 712, 724, 736, 738, 737, 740, 748]],\n   ['idle', 'idle', 'idle', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool', 'cool']],\n  ['control: scenario 2',\n   [680, 710, [674, 681, 688, 699, 718, 698, 716, 709, 691, 672, 678, 701, 724, 699, 683, 698, 691, 701]],\n   ['idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'cool',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle']]],\n [['regression: scenario 10',\n   [680, 700, [693, 681, 656, 676, 697, 710, 694, 681, 682, 707, 717, 711, 736, 731, 735]],\n   ['idle',\n    'idle',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'cool',\n    'cool',\n    'cool']],\n  ['regression: scenario 52',\n   [680, 700, [670, 669, 652, 663, 640, 620, 634, 649, 660, 680]],\n   ['idle', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'idle']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['control: scenario 1',\n   [680, 710, [758, 778, 769, 788, 780, 787, 790, 773, 789, 766, 785, 779, 790, 790, 790, 777, 790]],\n   ['cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool']],\n  ['regression: scenario 2',\n   [680, 740, [646, 654, 672, 672, 692, 717, 736, 759, 769, 790, 790]],\n   ['heat', 'heat', 'heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']]],\n [['regression: scenario 9',\n   [680, 690, [659, 637, 655, 663, 655, 654, 639, 635, 631, 656, 667, 672, 683, 704, 683, 696, 718]],\n   ['heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'idle',\n    'idle',\n    'idle']],\n  ['regression: scenario 35',\n   [680,\n    690,\n    [712,\n     690,\n     682,\n     662,\n     680,\n     655,\n     665,\n     643,\n     622,\n     636,\n     657,\n     681,\n     658,\n     663,\n     656,\n     663,\n     649,\n     661,\n     657,\n     643,\n     667]],\n   ['idle',\n    'idle',\n    'idle',\n    'heat',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['regression: scenario 1',\n   [680,\n    690,\n    [671, 646, 636, 635, 620, 625, 635, 653, 659, 636, 645, 633, 620, 628, 620, 638, 653, 655, 666, 678]],\n   ['idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat']],\n  ['regression: scenario 2',\n   [680, 740, [655, 638, 663, 641, 622, 636, 628, 621, 621, 620, 635, 632, 644, 651, 656, 675, 687]],\n   ['heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle']]],\n [['regression: scenario 19',\n   [680,\n    690,\n    [644, 668, 674, 684, 659, 674, 661, 653, 633, 642, 656, 675, 656, 679, 675, 677, 700, 714, 720]],\n   ['heat',\n    'heat',\n    'heat',\n    'idle',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'heat',\n    'idle',\n    'idle',\n    'idle']],\n  ['regression: exact thresholds',\n   [680, 720, [670, 669, 680, 731, 730, 720, 721]],\n   ['idle', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle']],\n  ['control: heat then locked cool',\n   [680, 700, [650, 660, 690, 700, 712, 725, 725, 725, 715, 710]],\n   ['heat', 'heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool', 'idle']],\n  ['control: short heat cycle then hot',\n   [680, 760, [660, 685, 790, 790, 790, 790, 790, 790]],\n   ['heat', 'idle', 'idle', 'idle', 'idle', 'idle', 'cool', 'cool']],\n  ['control: deadband squeeze',\n   [700, 705, [740, 741, 735, 730, 729]],\n   ['idle', 'cool', 'cool', 'idle', 'idle']],\n  ['control: scenario 1',\n   [680, 720, [774, 779, 785, 790, 790, 781, 778, 777, 770, 767, 743, 730, 708, 690]],\n   ['cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'idle',\n    'idle']],\n  ['control: scenario 2',\n   [680,\n    710,\n    [701,\n     679,\n     702,\n     721,\n     727,\n     748,\n     743,\n     720,\n     741,\n     738,\n     762,\n     769,\n     758,\n     740,\n     744,\n     725,\n     748,\n     728,\n     742,\n     755,\n     769]],\n   ['idle',\n    'idle',\n    'idle',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool',\n    'cool']],\n  ['control: scenario 3',\n   [680, 720, [645, 664, 650, 632, 620, 628, 652, 666, 661, 660, 644]],\n   ['heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat', 'heat']]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"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.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-hvac-thermostat-control-auto-changeover-deadband-heat-end-point","generated_at":"2026-09-29T14:51:44.989970+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"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.","root_cause":"The heat end test uses heat_sp - differential.","sha256":"3274723f79d3975b3942d5c3969b431429658275ef93d23e37136d873671d7b5","title":"Heating call ends at the start threshold instead of at setpoint · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verified":true,"visibility":"public","verification":{"attempt":{"elapsed_ms":41.853,"exit_code":1,"observations":[{"actual":["heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","idle","idle","heat","heat","heat","heat","heat","heat","heat","heat"],"check":"regression: scenario 3","expected":["heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","idle","idle","heat","heat","heat","heat","heat","heat","heat","heat"],"passed":true},{"actual":["idle","heat","heat","idle","idle","idle","idle"],"check":"regression: exact thresholds","expected":["idle","heat","idle","idle","idle","idle","idle"],"passed":false},{"actual":["heat","heat","idle","idle","idle","idle","idle","cool","cool","idle"],"check":"control: heat then locked cool","expected":["heat","heat","idle","idle","idle","idle","idle","cool","cool","idle"],"passed":true},{"actual":["heat","idle","idle","idle","idle","idle","cool","cool"],"check":"control: short heat cycle then hot","expected":["heat","idle","idle","idle","idle","idle","cool","cool"],"passed":true},{"actual":["idle","cool","cool","idle","idle"],"check":"control: deadband squeeze","expected":["idle","cool","cool","idle","idle"],"passed":true},{"actual":["idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle"],"check":"control: scenario 1","expected":["idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle"],"passed":true},{"actual":["idle","idle","idle","idle","cool","cool","cool","cool","cool","cool","cool","cool"],"check":"control: scenario 2","expected":["idle","idle","idle","idle","cool","cool","cool","cool","cool","cool","cool","cool"],"passed":true},{"actual":["idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","cool","idle","idle","cool","cool"],"check":"control: scenario 4","expected":["idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","cool","idle","idle","cool","cool"],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: scenario 3\", \"actual\": [\"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"idle\", \"idle\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\"], \"expected\": [\"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"idle\", \"idle\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\"], \"passed\": true}, {\"check\": \"regression: exact thresholds\", \"actual\": [\"idle\", \"heat\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\"], \"expected\": [\"idle\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\"], \"passed\": false}, {\"check\": \"control: heat then locked cool\", \"actual\": [\"heat\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\", \"idle\"], \"expected\": [\"heat\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\", \"idle\"], \"passed\": true}, {\"check\": \"control: short heat cycle then hot\", \"actual\": [\"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\"], \"expected\": [\"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\"], \"passed\": true}, {\"check\": \"control: deadband squeeze\", \"actual\": [\"idle\", \"cool\", \"cool\", \"idle\", \"idle\"], \"expected\": [\"idle\", \"cool\", \"cool\", \"idle\", \"idle\"], \"passed\": true}, {\"check\": \"control: scenario 1\", \"actual\": [\"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\"], \"expected\": [\"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\"], \"passed\": true}, {\"check\": \"control: scenario 2\", \"actual\": [\"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\"], \"expected\": [\"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\"], \"passed\": true}, {\"check\": \"control: scenario 4\", \"actual\": [\"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"idle\", \"idle\", \"cool\", \"cool\"], \"expected\": [\"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"idle\", \"idle\", \"cool\", \"cool\"], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":41.286,"exit_code":1,"observations":[{"actual":["heat","heat","heat","heat","heat","heat","heat","heat","idle","heat","idle","idle","idle","idle","heat","heat","idle","heat","heat","heat","heat","idle"],"check":"regression: scenario 3","expected":["heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","heat","idle","idle","heat","heat","heat","heat","heat","heat","heat","heat"],"passed":false},{"actual":["idle","heat","idle","idle","idle","idle","idle"],"check":"regression: exact thresholds","expected":["idle","heat","idle","idle","idle","idle","idle"],"passed":true},{"actual":["heat","heat","idle","idle","idle","idle","idle","cool","cool","idle"],"check":"control: heat then locked cool","expected":["heat","heat","idle","idle","idle","idle","idle","cool","cool","idle"],"passed":true},{"actual":["heat","idle","idle","idle","idle","idle","cool","cool"],"check":"control: short heat cycle then hot","expected":["heat","idle","idle","idle","idle","idle","cool","cool"],"passed":true},{"actual":["idle","cool","cool","idle","idle"],"check":"control: deadband squeeze","expected":["idle","cool","cool","idle","idle"],"passed":true},{"actual":["idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle"],"check":"control: scenario 1","expected":["idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle"],"passed":true},{"actual":["idle","idle","idle","idle","cool","cool","cool","cool","cool","cool","cool","cool"],"check":"control: scenario 2","expected":["idle","idle","idle","idle","cool","cool","cool","cool","cool","cool","cool","cool"],"passed":true},{"actual":["idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","cool","idle","idle","cool","cool"],"check":"control: scenario 4","expected":["idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","idle","cool","idle","idle","cool","cool"],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: scenario 3\", \"actual\": [\"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"idle\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"heat\", \"heat\", \"idle\", \"heat\", \"heat\", \"heat\", \"heat\", \"idle\"], \"expected\": [\"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"idle\", \"idle\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\", \"heat\"], \"passed\": false}, {\"check\": \"regression: exact thresholds\", \"actual\": [\"idle\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\"], \"expected\": [\"idle\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\"], \"passed\": true}, {\"check\": \"control: heat then locked cool\", \"actual\": [\"heat\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\", \"idle\"], \"expected\": [\"heat\", \"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\", \"idle\"], \"passed\": true}, {\"check\": \"control: short heat cycle then hot\", \"actual\": [\"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\"], \"expected\": [\"heat\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\"], \"passed\": true}, {\"check\": \"control: deadband squeeze\", \"actual\": [\"idle\", \"cool\", \"cool\", \"idle\", \"idle\"], \"expected\": [\"idle\", \"cool\", \"cool\", \"idle\", \"idle\"], \"passed\": true}, {\"check\": \"control: scenario 1\", \"actual\": [\"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\"], \"expected\": [\"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\"], \"passed\": true}, {\"check\": \"control: scenario 2\", \"actual\": [\"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\"], \"expected\": [\"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\", \"cool\"], \"passed\": true}, {\"check\": \"control: scenario 4\", \"actual\": [\"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"idle\", \"idle\", \"cool\", \"cool\"], \"expected\": [\"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"idle\", \"cool\", \"idle\", \"idle\", \"cool\", \"cool\"], \"passed\": true}], \"passed\": false}\n"}},"member_only":{"stages":["fixed"],"fields":["implementations.fixed","verification.fixed","harness","repair"],"note":"The verified repair, its recorded checks, the repair description, and the scoring harness are available to members."}}