{"abstract":"Pressing the arrows during a vacation hold makes the new setpoint stick past the next period.","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":"Ignoring temporary holds during a permanent hold drops the user's adjustment.","family":"w2-hvac-thermostat-control-setpoint-hold-override-hold-kind-replacement","id":"FA-92496","implementations":{"attempt":{"sha256":"539cde4bc3cc4b3b681c4b1f2a5d0d179aca40e31e0407c160dc0f25211ffb36","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 = max(500, min(900, sp))\n            if hold is None or hold[0] != 'perm' or kind == 'perm':\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: 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: 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: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: 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  ['control: 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: 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: 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  ['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: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: 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  ['regression: 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 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: scenario 29',\n   [[[0, 600, 'resume'],\n     [0, 600, ['perm', 841]],\n     [0, 600, None],\n     [0, 600, None],\n     [1, 700, None],\n     [1, 700, None],\n     [1, 700, ['temp', 875]],\n     [2, 600, None],\n     [2, 600, None],\n     [3, 600, ['perm', 698]],\n     [3, 600, None],\n     [3, 600, None],\n     [3, 600, ['perm', 580]],\n     [4, 600, None],\n     [4, 600, ['perm', 699]]]],\n   [600, 841, 841, 841, 841, 841, 875, 600, 600, 698, 698, 698, 580, 580, 699]],\n  ['regression: scenario 4',\n   [[[1, 700, ['perm', 595]],\n     [2, 600, None],\n     [2, 600, ['perm', 854]],\n     [3, 600, 'resume'],\n     [3, 600, ['perm', 923]],\n     [3, 600, ['perm', 783]],\n     [3, 600, None],\n     [3, 600, ['temp', 512]]]],\n   [595, 595, 854, 600, 900, 783, 783, 512]],\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  ['regression: 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: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['control: 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  ['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 [['regression: scenario 18',\n   [[[0, 700, ['perm', 651]],\n     [0, 700, None],\n     [1, 700, ['temp', 753]],\n     [2, 600, None],\n     [2, 600, None],\n     [3, 680, ['perm', 755]],\n     [3, 680, 'resume'],\n     [4, 700, None],\n     [4, 700, None],\n     [4, 700, ['temp', 927]]]],\n   [651, 651, 753, 600, 600, 755, 680, 700, 700, 900]],\n  ['regression: 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: 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  ['regression: 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: 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 3',\n   [[[0, 680, None],\n     [1, 680, None],\n     [2, 600, 'resume'],\n     [2, 600, None],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, 'resume'],\n     [4, 600, None],\n     [4, 600, None],\n     [4, 600, None],\n     [5, 620, ['temp', 645]],\n     [6, 700, None]]],\n   [680, 680, 600, 600, 700, 700, 700, 700, 600, 600, 600, 645, 700]]],\n [['regression: scenario 16',\n   [[[0, 600, ['temp', 465]],\n     [0, 600, ['perm', 908]],\n     [0, 600, None],\n     [1, 600, None],\n     [2, 600, None],\n     [2, 600, ['temp', 601]],\n     [2, 600, None],\n     [2, 600, None],\n     [2, 600, None],\n     [3, 700, None],\n     [3, 700, ['perm', 598]],\n     [3, 700, None],\n     [4, 700, None],\n     [4, 700, ['temp', 671]]]],\n   [500, 900, 900, 900, 900, 601, 601, 601, 601, 700, 598, 598, 598, 671]],\n  ['regression: scenario 5',\n   [[[1, 680, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, 'resume'],\n     [2, 700, 'resume'],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, ['perm', 533]],\n     [2, 700, None],\n     [2, 700, ['temp', 892]],\n     [2, 700, ['temp', 859]],\n     [2, 700, None]]],\n   [680, 700, 700, 700, 700, 700, 700, 700, 700, 533, 533, 892, 859, 859]],\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  ['regression: 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: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: 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":"c4bdc62e635bd3e8a1d95a470e90768666c780ee2c9dfd18c97de1d251854f86","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 = max(500, min(900, sp))\n            hold = [kind if hold is None or hold[0] != 'perm' else 'perm', 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: 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: 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: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: 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  ['control: 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: 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: 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  ['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: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: 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  ['regression: 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 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: scenario 29',\n   [[[0, 600, 'resume'],\n     [0, 600, ['perm', 841]],\n     [0, 600, None],\n     [0, 600, None],\n     [1, 700, None],\n     [1, 700, None],\n     [1, 700, ['temp', 875]],\n     [2, 600, None],\n     [2, 600, None],\n     [3, 600, ['perm', 698]],\n     [3, 600, None],\n     [3, 600, None],\n     [3, 600, ['perm', 580]],\n     [4, 600, None],\n     [4, 600, ['perm', 699]]]],\n   [600, 841, 841, 841, 841, 841, 875, 600, 600, 698, 698, 698, 580, 580, 699]],\n  ['regression: scenario 4',\n   [[[1, 700, ['perm', 595]],\n     [2, 600, None],\n     [2, 600, ['perm', 854]],\n     [3, 600, 'resume'],\n     [3, 600, ['perm', 923]],\n     [3, 600, ['perm', 783]],\n     [3, 600, None],\n     [3, 600, ['temp', 512]]]],\n   [595, 595, 854, 600, 900, 783, 783, 512]],\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  ['regression: 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: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['control: 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  ['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 [['regression: scenario 18',\n   [[[0, 700, ['perm', 651]],\n     [0, 700, None],\n     [1, 700, ['temp', 753]],\n     [2, 600, None],\n     [2, 600, None],\n     [3, 680, ['perm', 755]],\n     [3, 680, 'resume'],\n     [4, 700, None],\n     [4, 700, None],\n     [4, 700, ['temp', 927]]]],\n   [651, 651, 753, 600, 600, 755, 680, 700, 700, 900]],\n  ['regression: 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: 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  ['regression: 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: 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 3',\n   [[[0, 680, None],\n     [1, 680, None],\n     [2, 600, 'resume'],\n     [2, 600, None],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, None],\n     [3, 700, 'resume'],\n     [4, 600, None],\n     [4, 600, None],\n     [4, 600, None],\n     [5, 620, ['temp', 645]],\n     [6, 700, None]]],\n   [680, 680, 600, 600, 700, 700, 700, 700, 600, 600, 600, 645, 700]]],\n [['regression: scenario 16',\n   [[[0, 600, ['temp', 465]],\n     [0, 600, ['perm', 908]],\n     [0, 600, None],\n     [1, 600, None],\n     [2, 600, None],\n     [2, 600, ['temp', 601]],\n     [2, 600, None],\n     [2, 600, None],\n     [2, 600, None],\n     [3, 700, None],\n     [3, 700, ['perm', 598]],\n     [3, 700, None],\n     [4, 700, None],\n     [4, 700, ['temp', 671]]]],\n   [500, 900, 900, 900, 900, 601, 601, 601, 601, 700, 598, 598, 598, 671]],\n  ['regression: scenario 5',\n   [[[1, 680, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, 'resume'],\n     [2, 700, 'resume'],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, None],\n     [2, 700, ['perm', 533]],\n     [2, 700, None],\n     [2, 700, ['temp', 892]],\n     [2, 700, ['temp', 859]],\n     [2, 700, None]]],\n   [680, 700, 700, 700, 700, 700, 700, 700, 700, 533, 533, 892, 859, 859]],\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  ['regression: 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: clamp low', [[[1, 680, ['perm', 300]], [2, 620, None]]], [500, 500]],\n  ['regression: 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-kind-replacement","generated_at":"2026-09-29T14:51:46.315990+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":"A new hold keeps the permanent kind if one was active.","sha256":"d7dea9ab726e83b0f4b23a26ba3d1694bbc6a698810bdab2942837111369bbe2","title":"A temporary hold set during a permanent hold becomes permanent · 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.645,"exit_code":1,"observations":[{"actual":[680,720,720,620,900,900,900,900,650],"check":"regression: hold lifecycle","expected":[680,720,720,620,900,900,500,650,650],"passed":false},{"actual":[720,720,720,720],"check":"regression: temporary over permanent","expected":[720,690,690,640],"passed":false},{"actual":[700,620,710,710,600],"check":"control: second temporary hold","expected":[700,620,710,710,600],"passed":true},{"actual":[500,500],"check":"control: clamp low","expected":[500,500],"passed":true},{"actual":[690,690,700,700,700,600,600,856,777,777,777,777,777,777,777,777],"check":"regression: scenario 1","expected":[690,690,700,700,700,600,600,856,777,777,777,764,764,600,726,726],"passed":false},{"actual":[620,540,540,540,540,540,500,500,500],"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":"control: 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, 900, 900, 650], \"expected\": [680, 720, 720, 620, 900, 900, 500, 650, 650], \"passed\": false}, {\"check\": \"regression: temporary over permanent\", \"actual\": [720, 720, 720, 720], \"expected\": [720, 690, 690, 640], \"passed\": false}, {\"check\": \"control: second temporary hold\", \"actual\": [700, 620, 710, 710, 600], \"expected\": [700, 620, 710, 710, 600], \"passed\": true}, {\"check\": \"control: clamp low\", \"actual\": [500, 500], \"expected\": [500, 500], \"passed\": true}, {\"check\": \"regression: scenario 1\", \"actual\": [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 777, 777, 777, 777, 777], \"expected\": [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 600, 726, 726], \"passed\": false}, {\"check\": \"regression: scenario 2\", \"actual\": [620, 540, 540, 540, 540, 540, 500, 500, 500], \"expected\": [620, 540, 540, 540, 863, 600, 500, 500, 500], \"passed\": false}, {\"check\": \"control: 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.235,"exit_code":1,"observations":[{"actual":[680,720,720,620,900,900,500,500,650],"check":"regression: hold lifecycle","expected":[680,720,720,620,900,900,500,650,650],"passed":false},{"actual":[720,690,690,690],"check":"regression: temporary over permanent","expected":[720,690,690,640],"passed":false},{"actual":[700,620,710,710,600],"check":"control: second temporary hold","expected":[700,620,710,710,600],"passed":true},{"actual":[500,500],"check":"control: clamp low","expected":[500,500],"passed":true},{"actual":[690,690,700,700,700,600,600,856,777,777,777,764,764,764,726,726],"check":"regression: scenario 1","expected":[690,690,700,700,700,600,600,856,777,777,777,764,764,600,726,726],"passed":false},{"actual":[620,540,540,540,863,863,500,500,500],"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":"control: 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, 500, 500, 650], \"expected\": [680, 720, 720, 620, 900, 900, 500, 650, 650], \"passed\": false}, {\"check\": \"regression: temporary over permanent\", \"actual\": [720, 690, 690, 690], \"expected\": [720, 690, 690, 640], \"passed\": false}, {\"check\": \"control: second temporary hold\", \"actual\": [700, 620, 710, 710, 600], \"expected\": [700, 620, 710, 710, 600], \"passed\": true}, {\"check\": \"control: clamp low\", \"actual\": [500, 500], \"expected\": [500, 500], \"passed\": true}, {\"check\": \"regression: scenario 1\", \"actual\": [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 764, 726, 726], \"expected\": [690, 690, 700, 700, 700, 600, 600, 856, 777, 777, 777, 764, 764, 600, 726, 726], \"passed\": false}, {\"check\": \"regression: scenario 2\", \"actual\": [620, 540, 540, 540, 863, 863, 500, 500, 500], \"expected\": [620, 540, 540, 540, 863, 600, 500, 500, 500], \"passed\": false}, {\"check\": \"control: 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"}},"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."}}