{"abstract":"A remote or keypad hold can command 40 F or 95 F.","category":"HVAC thermostat control","checks":8,"contract":"Thermostat hold logic; samples are [schedule_period_id, scheduled_setpoint, action] where action is None, \"resume\", [\"temp\", sp] or [\"perm\", sp]. A hold setpoint is clamped to 50.0-90.0 F (500-900 tenths). A temporary hold lasts until the schedule period id changes from the one in which the hold was set; a permanent hold lasts until resume. A new hold of either kind replaces the current hold. Return the effective setpoint per sample.","contract_signature":"samples","evaluation_group":"w2-hvac-thermostat-control-setpoint-hold-override","failed_approach":"Clamping only the upper limit still accepts unsafe low setpoints.","family":"w2-hvac-thermostat-control-setpoint-hold-override-hold-limit-clamp","id":"FA-92491","implementations":{"attempt":{"sha256":"a45248a2e148f90e6c6a3acac1618727012e9b0851ebb75926c34703623cf9e0","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(samples):\n    hold = None\n    hold_period = None\n    out = []\n    for period, sched, action in samples:\n        if action == 'resume':\n            hold = None\n        elif action is not None:\n            kind, sp = action\n            sp = min(900, sp)\n            hold = [kind, sp]\n            hold_period = period\n        if hold is not None and hold[0] == 'temp' and period != hold_period:\n            hold = None\n        out.append(sched if hold is None else hold[1])\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['control: scenario 1',\n   [[[0, 700, ['perm', 690]],\n     [0, 700, None],\n     [0, 700, 'resume'],\n     [1, 700, None],\n     [1, 700, None],\n     [2, 600, None],\n     [2, 600, None],\n     [3, 680, ['perm', 856]],\n     [4, 620, ['perm', 777]],\n     [4, 620, None],\n     [4, 620, None],\n     [5, 600, ['temp', 764]],\n     [5, 600, None],\n     [6, 600, None],\n     [7, 600, ['temp', 726]],\n     [7, 600, None]]],\n   [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 600, 726, 726]],\n  ['regression: scenario 2',\n   [[[1, 620, None],\n     [1, 620, ['perm', 540]],\n     [1, 620, None],\n     [1, 620, None],\n     [1, 620, ['temp', 863]],\n     [2, 600, None],\n     [3, 700, ['perm', 476]],\n     [3, 700, None],\n     [3, 700, None]]],\n   [620, 540, 540, 540, 863, 600, 500, 500, 500]],\n  ['regression: scenario 3',\n   [[[1, 620, ['temp', 657]],\n     [1, 620, ['temp', 940]],\n     [1, 620, None],\n     [1, 620, None],\n     [1, 620, None],\n     [2, 700, 'resume'],\n     [2, 700, ['temp', 641]],\n     [3, 620, None]]],\n   [657, 900, 900, 900, 900, 700, 641, 620]],\n  ['control: scenario 4',\n   [[[0, 700, ['temp', 891]],\n     [0, 700, None],\n     [0, 700, None],\n     [0, 700, ['temp', 877]],\n     [0, 700, None],\n     [0, 700, None],\n     [1, 600, None],\n     [1, 600, 'resume'],\n     [2, 620, ['perm', 514]]]],\n   [891, 891, 891, 877, 877, 877, 600, 600, 514]]],\n [['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: scenario 4',\n   [[[0, 680, None],\n     [1, 600, ['temp', 779]],\n     [1, 600, ['temp', 782]],\n     [2, 680, None],\n     [3, 700, ['perm', 454]],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, ['temp', 831]],\n     [3, 700, None],\n     [3, 700, None]]],\n   [680, 779, 782, 680, 500, 500, 500, 500, 500, 831, 831, 831]],\n  ['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['control: scenario 1',\n   [[[1, 700, 'resume'],\n     [1, 700, ['perm', 548]],\n     [1, 700, None],\n     [1, 700, None],\n     [2, 700, None],\n     [3, 620, None],\n     [4, 620, None],\n     [5, 680, None],\n     [5, 680, ['temp', 806]],\n     [5, 680, None],\n     [5, 680, None],\n     [6, 700, None],\n     [6, 700, None],\n     [6, 700, None]]],\n   [700, 548, 548, 548, 548, 548, 548, 548, 806, 806, 806, 700, 700, 700]],\n  ['control: scenario 2',\n   [[[0, 680, None],\n     [0, 680, None],\n     [0, 680, None],\n     [0, 680, None],\n     [0, 680, None],\n     [0, 680, None],\n     [0, 680, ['temp', 520]],\n     [0, 680, None],\n     [1, 680, None],\n     [2, 620, None],\n     [3, 680, ['perm', 745]],\n     [3, 680, None],\n     [3, 680, None],\n     [4, 680, None],\n     [5, 700, ['temp', 765]],\n     [5, 700, None]]],\n   [680, 680, 680, 680, 680, 680, 520, 520, 680, 620, 745, 745, 745, 745, 765, 765]],\n  ['control: scenario 3',\n   [[[0, 620, None],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, ['perm', 700]],\n     [0, 620, ['temp', 750]],\n     [1, 620, None],\n     [2, 620, None],\n     [2, 620, None]]],\n   [620, 620, 620, 620, 620, 700, 750, 620, 620, 620]]],\n [['regression: scenario 1',\n   [[[0, 620, None],\n     [1, 680, None],\n     [1, 680, None],\n     [1, 680, None],\n     [2, 680, ['temp', 617]],\n     [2, 680, None],\n     [2, 680, ['perm', 816]],\n     [3, 620, ['perm', 930]],\n     [3, 620, None]]],\n   [620, 680, 680, 680, 617, 617, 816, 900, 900]],\n  ['regression: scenario 5',\n   [[[0, 680, None],\n     [0, 680, None],\n     [0, 680, ['temp', 811]],\n     [0, 680, None],\n     [1, 700, None],\n     [1, 700, ['temp', 458]],\n     [2, 620, ['perm', 612]],\n     [3, 600, None],\n     [3, 600, None],\n     [3, 600, ['perm', 764]],\n     [3, 600, ['perm', 458]],\n     [3, 600, None],\n     [4, 600, None]]],\n   [680, 680, 811, 811, 700, 500, 612, 612, 612, 764, 500, 500, 500]],\n  ['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['control: scenario 2',\n   [[[0, 620, 'resume'],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, 'resume'],\n     [1, 620, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, None],\n     [3, 620, None],\n     [3, 620, ['perm', 870]],\n     [3, 620, None]]],\n   [620, 620, 620, 620, 620, 620, 700, 700, 700, 700, 620, 870, 870]],\n  ['control: scenario 3',\n   [[[0, 680, 'resume'],\n     [1, 700, None],\n     [1, 700, None],\n     [1, 700, None],\n     [2, 620, None],\n     [2, 620, 'resume'],\n     [2, 620, None],\n     [2, 620, ['temp', 685]],\n     [2, 620, ['perm', 890]],\n     [2, 620, ['perm', 678]]]],\n   [680, 700, 700, 700, 620, 620, 620, 685, 890, 678]]],\n [['regression: scenario 6',\n   [[[0, 700, None],\n     [0, 700, None],\n     [0, 700, ['perm', 473]],\n     [0, 700, None],\n     [0, 700, None],\n     [0, 700, None],\n     [0, 700, None],\n     [1, 600, None],\n     [1, 600, None],\n     [2, 600, None],\n     [3, 680, None]]],\n   [700, 700, 500, 500, 500, 500, 500, 500, 500, 500, 500]],\n  ['regression: scenario 20',\n   [[[1, 620, None],\n     [2, 620, None],\n     [3, 680, None],\n     [3, 680, ['perm', 458]],\n     [4, 620, None],\n     [4, 620, None],\n     [4, 620, None],\n     [4, 620, 'resume']]],\n   [620, 620, 680, 500, 500, 500, 500, 620]],\n  ['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: scenario 1',\n   [[[1, 700, ['temp', 847]],\n     [1, 700, None],\n     [1, 700, None],\n     [1, 700, 'resume'],\n     [1, 700, None],\n     [1, 700, None],\n     [1, 700, ['perm', 465]],\n     [1, 700, None],\n     [2, 600, ['temp', 552]],\n     [2, 600, None],\n     [2, 600, ['temp', 898]]]],\n   [847, 847, 847, 700, 700, 700, 500, 500, 552, 552, 898]],\n  ['control: scenario 2',\n   [[[0, 680, 'resume'],\n     [0, 680, None],\n     [0, 680, ['perm', 681]],\n     [0, 680, None],\n     [1, 680, None],\n     [1, 680, None],\n     [1, 680, None],\n     [1, 680, ['temp', 832]],\n     [1, 680, ['temp', 511]],\n     [1, 680, ['perm', 779]],\n     [1, 680, ['temp', 724]],\n     [2, 700, 'resume'],\n     [3, 680, None],\n     [3, 680, 'resume']]],\n   [680, 680, 681, 681, 681, 681, 681, 832, 511, 779, 724, 700, 680, 680]]],\n [['regression: scenario 14',\n   [[[0, 700, None],\n     [1, 600, ['temp', 689]],\n     [2, 600, ['temp', 824]],\n     [2, 600, None],\n     [3, 700, ['perm', 944]],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, ['perm', 527]],\n     [3, 700, ['temp', 867]]]],\n   [700, 689, 824, 824, 900, 900, 900, 527, 867]],\n  ['regression: scenario 23',\n   [[[0, 620, None],\n     [0, 620, None],\n     [1, 600, ['temp', 453]],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, ['perm', 679]],\n     [3, 620, None],\n     [3, 620, ['perm', 913]],\n     [4, 680, ['temp', 514]],\n     [4, 680, None],\n     [4, 680, ['perm', 613]],\n     [4, 680, None],\n     [4, 680, None],\n     [5, 700, None],\n     [5, 700, None]]],\n   [620, 620, 500, 700, 700, 679, 679, 900, 514, 514, 613, 613, 613, 613, 613]],\n  ['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['control: scenario 1',\n   [[[0, 700, None],\n     [0, 700, None],\n     [0, 700, None],\n     [0, 700, ['perm', 578]],\n     [1, 600, 'resume'],\n     [2, 600, ['temp', 629]],\n     [3, 700, None],\n     [3, 700, ['perm', 796]],\n     [3, 700, ['temp', 558]],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, ['temp', 796]],\n     [4, 700, None],\n     [4, 700, None],\n     [4, 700, None],\n     [4, 700, None]]],\n   [700, 700, 700, 578, 600, 629, 700, 796, 558, 558, 558, 796, 700, 700, 700, 700]],\n  ['control: scenario 2',\n   [[[0, 600, None],\n     [0, 600, None],\n     [0, 600, None],\n     [0, 600, None],\n     [0, 600, None],\n     [1, 680, ['temp', 866]],\n     [1, 680, None],\n     [1, 680, ['temp', 591]],\n     [1, 680, ['temp', 671]],\n     [2, 700, None],\n     [2, 700, None]]],\n   [600, 600, 600, 600, 600, 866, 866, 591, 671, 700, 700]]]]\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":"3a561556cb9b0af148637a1f2f327998cc3c404305949cd822dcea2a3a345ba2","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(samples):\n    hold = None\n    hold_period = None\n    out = []\n    for period, sched, action in samples:\n        if action == 'resume':\n            hold = None\n        elif action is not None:\n            kind, sp = action\n            hold = [kind, sp]\n            hold_period = period\n        if hold is not None and hold[0] == 'temp' and period != hold_period:\n            hold = None\n        out.append(sched if hold is None else hold[1])\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['control: scenario 1',\n   [[[0, 700, ['perm', 690]],\n     [0, 700, None],\n     [0, 700, 'resume'],\n     [1, 700, None],\n     [1, 700, None],\n     [2, 600, None],\n     [2, 600, None],\n     [3, 680, ['perm', 856]],\n     [4, 620, ['perm', 777]],\n     [4, 620, None],\n     [4, 620, None],\n     [5, 600, ['temp', 764]],\n     [5, 600, None],\n     [6, 600, None],\n     [7, 600, ['temp', 726]],\n     [7, 600, None]]],\n   [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 600, 726, 726]],\n  ['regression: scenario 2',\n   [[[1, 620, None],\n     [1, 620, ['perm', 540]],\n     [1, 620, None],\n     [1, 620, None],\n     [1, 620, ['temp', 863]],\n     [2, 600, None],\n     [3, 700, ['perm', 476]],\n     [3, 700, None],\n     [3, 700, None]]],\n   [620, 540, 540, 540, 863, 600, 500, 500, 500]],\n  ['regression: scenario 3',\n   [[[1, 620, ['temp', 657]],\n     [1, 620, ['temp', 940]],\n     [1, 620, None],\n     [1, 620, None],\n     [1, 620, None],\n     [2, 700, 'resume'],\n     [2, 700, ['temp', 641]],\n     [3, 620, None]]],\n   [657, 900, 900, 900, 900, 700, 641, 620]],\n  ['control: scenario 4',\n   [[[0, 700, ['temp', 891]],\n     [0, 700, None],\n     [0, 700, None],\n     [0, 700, ['temp', 877]],\n     [0, 700, None],\n     [0, 700, None],\n     [1, 600, None],\n     [1, 600, 'resume'],\n     [2, 620, ['perm', 514]]]],\n   [891, 891, 891, 877, 877, 877, 600, 600, 514]]],\n [['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: scenario 4',\n   [[[0, 680, None],\n     [1, 600, ['temp', 779]],\n     [1, 600, ['temp', 782]],\n     [2, 680, None],\n     [3, 700, ['perm', 454]],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, ['temp', 831]],\n     [3, 700, None],\n     [3, 700, None]]],\n   [680, 779, 782, 680, 500, 500, 500, 500, 500, 831, 831, 831]],\n  ['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['control: scenario 1',\n   [[[1, 700, 'resume'],\n     [1, 700, ['perm', 548]],\n     [1, 700, None],\n     [1, 700, None],\n     [2, 700, None],\n     [3, 620, None],\n     [4, 620, None],\n     [5, 680, None],\n     [5, 680, ['temp', 806]],\n     [5, 680, None],\n     [5, 680, None],\n     [6, 700, None],\n     [6, 700, None],\n     [6, 700, None]]],\n   [700, 548, 548, 548, 548, 548, 548, 548, 806, 806, 806, 700, 700, 700]],\n  ['control: scenario 2',\n   [[[0, 680, None],\n     [0, 680, None],\n     [0, 680, None],\n     [0, 680, None],\n     [0, 680, None],\n     [0, 680, None],\n     [0, 680, ['temp', 520]],\n     [0, 680, None],\n     [1, 680, None],\n     [2, 620, None],\n     [3, 680, ['perm', 745]],\n     [3, 680, None],\n     [3, 680, None],\n     [4, 680, None],\n     [5, 700, ['temp', 765]],\n     [5, 700, None]]],\n   [680, 680, 680, 680, 680, 680, 520, 520, 680, 620, 745, 745, 745, 745, 765, 765]],\n  ['control: scenario 3',\n   [[[0, 620, None],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, ['perm', 700]],\n     [0, 620, ['temp', 750]],\n     [1, 620, None],\n     [2, 620, None],\n     [2, 620, None]]],\n   [620, 620, 620, 620, 620, 700, 750, 620, 620, 620]]],\n [['regression: scenario 1',\n   [[[0, 620, None],\n     [1, 680, None],\n     [1, 680, None],\n     [1, 680, None],\n     [2, 680, ['temp', 617]],\n     [2, 680, None],\n     [2, 680, ['perm', 816]],\n     [3, 620, ['perm', 930]],\n     [3, 620, None]]],\n   [620, 680, 680, 680, 617, 617, 816, 900, 900]],\n  ['regression: scenario 5',\n   [[[0, 680, None],\n     [0, 680, None],\n     [0, 680, ['temp', 811]],\n     [0, 680, None],\n     [1, 700, None],\n     [1, 700, ['temp', 458]],\n     [2, 620, ['perm', 612]],\n     [3, 600, None],\n     [3, 600, None],\n     [3, 600, ['perm', 764]],\n     [3, 600, ['perm', 458]],\n     [3, 600, None],\n     [4, 600, None]]],\n   [680, 680, 811, 811, 700, 500, 612, 612, 612, 764, 500, 500, 500]],\n  ['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['control: scenario 2',\n   [[[0, 620, 'resume'],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, None],\n     [0, 620, 'resume'],\n     [1, 620, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, None],\n     [3, 620, None],\n     [3, 620, ['perm', 870]],\n     [3, 620, None]]],\n   [620, 620, 620, 620, 620, 620, 700, 700, 700, 700, 620, 870, 870]],\n  ['control: scenario 3',\n   [[[0, 680, 'resume'],\n     [1, 700, None],\n     [1, 700, None],\n     [1, 700, None],\n     [2, 620, None],\n     [2, 620, 'resume'],\n     [2, 620, None],\n     [2, 620, ['temp', 685]],\n     [2, 620, ['perm', 890]],\n     [2, 620, ['perm', 678]]]],\n   [680, 700, 700, 700, 620, 620, 620, 685, 890, 678]]],\n [['regression: scenario 6',\n   [[[0, 700, None],\n     [0, 700, None],\n     [0, 700, ['perm', 473]],\n     [0, 700, None],\n     [0, 700, None],\n     [0, 700, None],\n     [0, 700, None],\n     [1, 600, None],\n     [1, 600, None],\n     [2, 600, None],\n     [3, 680, None]]],\n   [700, 700, 500, 500, 500, 500, 500, 500, 500, 500, 500]],\n  ['regression: scenario 20',\n   [[[1, 620, None],\n     [2, 620, None],\n     [3, 680, None],\n     [3, 680, ['perm', 458]],\n     [4, 620, None],\n     [4, 620, None],\n     [4, 620, None],\n     [4, 620, 'resume']]],\n   [620, 620, 680, 500, 500, 500, 500, 620]],\n  ['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: scenario 1',\n   [[[1, 700, ['temp', 847]],\n     [1, 700, None],\n     [1, 700, None],\n     [1, 700, 'resume'],\n     [1, 700, None],\n     [1, 700, None],\n     [1, 700, ['perm', 465]],\n     [1, 700, None],\n     [2, 600, ['temp', 552]],\n     [2, 600, None],\n     [2, 600, ['temp', 898]]]],\n   [847, 847, 847, 700, 700, 700, 500, 500, 552, 552, 898]],\n  ['control: scenario 2',\n   [[[0, 680, 'resume'],\n     [0, 680, None],\n     [0, 680, ['perm', 681]],\n     [0, 680, None],\n     [1, 680, None],\n     [1, 680, None],\n     [1, 680, None],\n     [1, 680, ['temp', 832]],\n     [1, 680, ['temp', 511]],\n     [1, 680, ['perm', 779]],\n     [1, 680, ['temp', 724]],\n     [2, 700, 'resume'],\n     [3, 680, None],\n     [3, 680, 'resume']]],\n   [680, 680, 681, 681, 681, 681, 681, 832, 511, 779, 724, 700, 680, 680]]],\n [['regression: scenario 14',\n   [[[0, 700, None],\n     [1, 600, ['temp', 689]],\n     [2, 600, ['temp', 824]],\n     [2, 600, None],\n     [3, 700, ['perm', 944]],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, ['perm', 527]],\n     [3, 700, ['temp', 867]]]],\n   [700, 689, 824, 824, 900, 900, 900, 527, 867]],\n  ['regression: scenario 23',\n   [[[0, 620, None],\n     [0, 620, None],\n     [1, 600, ['temp', 453]],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, ['perm', 679]],\n     [3, 620, None],\n     [3, 620, ['perm', 913]],\n     [4, 680, ['temp', 514]],\n     [4, 680, None],\n     [4, 680, ['perm', 613]],\n     [4, 680, None],\n     [4, 680, None],\n     [5, 700, None],\n     [5, 700, None]]],\n   [620, 620, 500, 700, 700, 679, 679, 900, 514, 514, 613, 613, 613, 613, 613]],\n  ['regression: hold lifecycle',\n   [[[1, 680, None],\n     [1, 680, ['temp', 720]],\n     [1, 680, None],\n     [2, 620, None],\n     [2, 620, ['perm', 950]],\n     [3, 700, None],\n     [3, 700, ['temp', 400]],\n     [4, 650, None],\n     [4, 650, 'resume']]],\n   [680, 720, 720, 620, 900, 900, 500, 650, 650]],\n  ['control: second temporary hold',\n   [[[1, 680, ['temp', 700]], [2, 620, None], [3, 650, ['temp', 710]], [3, 650, None], [4, 600, None]]],\n   [700, 620, 710, 710, 600]],\n  ['control: temporary over permanent',\n   [[[1, 680, ['perm', 720]], [2, 620, ['temp', 690]], [2, 620, None], [3, 640, None]]],\n   [720, 690, 690, 640]],\n  ['regression: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['control: scenario 1',\n   [[[0, 700, None],\n     [0, 700, None],\n     [0, 700, None],\n     [0, 700, ['perm', 578]],\n     [1, 600, 'resume'],\n     [2, 600, ['temp', 629]],\n     [3, 700, None],\n     [3, 700, ['perm', 796]],\n     [3, 700, ['temp', 558]],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, ['temp', 796]],\n     [4, 700, None],\n     [4, 700, None],\n     [4, 700, None],\n     [4, 700, None]]],\n   [700, 700, 700, 578, 600, 629, 700, 796, 558, 558, 558, 796, 700, 700, 700, 700]],\n  ['control: scenario 2',\n   [[[0, 600, None],\n     [0, 600, None],\n     [0, 600, None],\n     [0, 600, None],\n     [0, 600, None],\n     [1, 680, ['temp', 866]],\n     [1, 680, None],\n     [1, 680, ['temp', 591]],\n     [1, 680, ['temp', 671]],\n     [2, 700, None],\n     [2, 700, None]]],\n   [600, 600, 600, 600, 600, 866, 866, 591, 671, 700, 700]]]]\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-setpoint-hold-override-hold-limit-clamp","generated_at":"2026-09-29T14:51:46.311845+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 hold setpoint is stored without clamping.","sha256":"9a1ed03a36c43c942795edc919238cf2e7b8bcb2154e65732d9ae63287b8111b","title":"Hold setpoint accepts values outside the thermostat limits · 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":42.06,"exit_code":1,"observations":[{"actual":[680,720,720,620,900,900,400,650,650],"check":"regression: hold lifecycle","expected":[680,720,720,620,900,900,500,650,650],"passed":false},{"actual":[300,300],"check":"regression: clamp low","expected":[500,500],"passed":false},{"actual":[700,620,710,710,600],"check":"control: second temporary hold","expected":[700,620,710,710,600],"passed":true},{"actual":[720,690,690,640],"check":"control: temporary over permanent","expected":[720,690,690,640],"passed":true},{"actual":[690,690,700,700,700,600,600,856,777,777,777,764,764,600,726,726],"check":"control: scenario 1","expected":[690,690,700,700,700,600,600,856,777,777,777,764,764,600,726,726],"passed":true},{"actual":[620,540,540,540,863,600,476,476,476],"check":"regression: scenario 2","expected":[620,540,540,540,863,600,500,500,500],"passed":false},{"actual":[657,900,900,900,900,700,641,620],"check":"regression: scenario 3","expected":[657,900,900,900,900,700,641,620],"passed":true},{"actual":[891,891,891,877,877,877,600,600,514],"check":"control: scenario 4","expected":[891,891,891,877,877,877,600,600,514],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: hold lifecycle\", \"actual\": [680, 720, 720, 620, 900, 900, 400, 650, 650], \"expected\": [680, 720, 720, 620, 900, 900, 500, 650, 650], \"passed\": false}, {\"check\": \"regression: clamp low\", \"actual\": [300, 300], \"expected\": [500, 500], \"passed\": false}, {\"check\": \"control: second temporary hold\", \"actual\": [700, 620, 710, 710, 600], \"expected\": [700, 620, 710, 710, 600], \"passed\": true}, {\"check\": \"control: temporary over permanent\", \"actual\": [720, 690, 690, 640], \"expected\": [720, 690, 690, 640], \"passed\": true}, {\"check\": \"control: scenario 1\", \"actual\": [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 600, 726, 726], \"expected\": [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 600, 726, 726], \"passed\": true}, {\"check\": \"regression: scenario 2\", \"actual\": [620, 540, 540, 540, 863, 600, 476, 476, 476], \"expected\": [620, 540, 540, 540, 863, 600, 500, 500, 500], \"passed\": false}, {\"check\": \"regression: scenario 3\", \"actual\": [657, 900, 900, 900, 900, 700, 641, 620], \"expected\": [657, 900, 900, 900, 900, 700, 641, 620], \"passed\": true}, {\"check\": \"control: scenario 4\", \"actual\": [891, 891, 891, 877, 877, 877, 600, 600, 514], \"expected\": [891, 891, 891, 877, 877, 877, 600, 600, 514], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":42.843,"exit_code":1,"observations":[{"actual":[680,720,720,620,950,950,400,650,650],"check":"regression: hold lifecycle","expected":[680,720,720,620,900,900,500,650,650],"passed":false},{"actual":[300,300],"check":"regression: clamp low","expected":[500,500],"passed":false},{"actual":[700,620,710,710,600],"check":"control: second temporary hold","expected":[700,620,710,710,600],"passed":true},{"actual":[720,690,690,640],"check":"control: temporary over permanent","expected":[720,690,690,640],"passed":true},{"actual":[690,690,700,700,700,600,600,856,777,777,777,764,764,600,726,726],"check":"control: scenario 1","expected":[690,690,700,700,700,600,600,856,777,777,777,764,764,600,726,726],"passed":true},{"actual":[620,540,540,540,863,600,476,476,476],"check":"regression: scenario 2","expected":[620,540,540,540,863,600,500,500,500],"passed":false},{"actual":[657,940,940,940,940,700,641,620],"check":"regression: scenario 3","expected":[657,900,900,900,900,700,641,620],"passed":false},{"actual":[891,891,891,877,877,877,600,600,514],"check":"control: scenario 4","expected":[891,891,891,877,877,877,600,600,514],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: hold lifecycle\", \"actual\": [680, 720, 720, 620, 950, 950, 400, 650, 650], \"expected\": [680, 720, 720, 620, 900, 900, 500, 650, 650], \"passed\": false}, {\"check\": \"regression: clamp low\", \"actual\": [300, 300], \"expected\": [500, 500], \"passed\": false}, {\"check\": \"control: second temporary hold\", \"actual\": [700, 620, 710, 710, 600], \"expected\": [700, 620, 710, 710, 600], \"passed\": true}, {\"check\": \"control: temporary over permanent\", \"actual\": [720, 690, 690, 640], \"expected\": [720, 690, 690, 640], \"passed\": true}, {\"check\": \"control: scenario 1\", \"actual\": [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 600, 726, 726], \"expected\": [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 600, 726, 726], \"passed\": true}, {\"check\": \"regression: scenario 2\", \"actual\": [620, 540, 540, 540, 863, 600, 476, 476, 476], \"expected\": [620, 540, 540, 540, 863, 600, 500, 500, 500], \"passed\": false}, {\"check\": \"regression: scenario 3\", \"actual\": [657, 940, 940, 940, 940, 700, 641, 620], \"expected\": [657, 900, 900, 900, 900, 700, 641, 620], \"passed\": false}, {\"check\": \"control: scenario 4\", \"actual\": [891, 891, 891, 877, 877, 877, 600, 600, 514], \"expected\": [891, 891, 891, 877, 877, 877, 600, 600, 514], \"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."}}