{"abstract":"Switching to Celsius lets the user walk the setpoint outside 45-90 F.","category":"HVAC thermostat control","checks":8,"contract":"Thermostat setpoint keypad. The setpoint is stored in tenths F. In C mode the display shows the stored value converted to C and rounded half up to 0.5 C; a press moves the displayed value by 0.5 C and stores exactly 320 + half_degrees*9 tenths F. In F mode the display rounds half up to whole F and a press moves the whole-degree value by 1 F. After each press the stored value is clamped to 45.0-90.0 F. Return [display, stored_tenths_F] per press.","evaluation_group":"w2-hvac-thermostat-control-setpoint-keypad-units","failed_approach":"Clamping inside the Fahrenheit branch only still lets Celsius presses escape the limits.","family":"w2-hvac-thermostat-control-setpoint-keypad-units-clamp-per-unit","id":"FA-92516","implementations":{"attempt":{"sha256":"e55be2a355222d1f471c765e5cf39256512fc340814bb6eb7c88df3ac5933408","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(unit, presses, start_f10):\n    f10 = start_f10\n    out = []\n    for p in presses:\n        step = 1 if p == 'up' else -1\n        if unit == 'C':\n            c_half = (2 * (f10 - 320) + 9) // 18\n            f10 = 320 + (c_half + step) * 9\n        else:\n            f_whole = (f10 + 5) // 10\n            f10 = max(450, min(900, (f_whole + step) * 10))\n        if unit == 'C':\n            c_half = (2 * (f10 - 320) + 9) // 18\n            out.append(['%d.%d' % (c_half // 2, 5 * (c_half % 2)), f10])\n        else:\n            out.append([str((f10 + 5) // 10), f10])\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]],\n  ['control: scenario 1',\n   ['F', ['down', 'down', 'up', 'up', 'up', 'down', 'down', 'up'], 716],\n   [['71', 710], ['70', 700], ['71', 710], ['72', 720], ['73', 730], ['72', 720], ['71', 710], ['72', 720]]],\n  ['control: scenario 2',\n   ['C', ['down', 'down', 'down', 'up', 'down', 'down', 'up'], 716],\n   [['21.5', 707],\n    ['21.0', 698],\n    ['20.5', 689],\n    ['21.0', 698],\n    ['20.5', 689],\n    ['20.0', 680],\n    ['20.5', 689]]]],\n [['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['regression: scenario 22',\n   ['C', ['down', 'down', 'up', 'down', 'down'], 445],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455], ['7.0', 450], ['7.0', 450]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]],\n  ['control: scenario 1',\n   ['F', ['down', 'down', 'up', 'up', 'down', 'down', 'down', 'up'], 652],\n   [['64', 640], ['63', 630], ['64', 640], ['65', 650], ['64', 640], ['63', 630], ['62', 620], ['63', 630]]]],\n [['regression: scenario 4',\n   ['C', ['down', 'up', 'down', 'down', 'down', 'down', 'down', 'up'], 445],\n   [['7.0', 450],\n    ['7.5', 455],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.5', 455]]],\n  ['regression: scenario 25',\n   ['C', ['down', 'down', 'down', 'up', 'down', 'up', 'up', 'up', 'down'], 905],\n   [['32.0', 896],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887],\n    ['32.0', 896],\n    ['32.0', 900],\n    ['31.5', 887]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]],\n [['regression: scenario 6',\n   ['C', ['up', 'up', 'down', 'down', 'down', 'down', 'down', 'down'], 905],\n   [['32.0', 900],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['30.5', 869],\n    ['30.0', 860],\n    ['29.5', 851],\n    ['29.0', 842]]],\n  ['regression: scenario 18',\n   ['C', ['up', 'up', 'down', 'up', 'up', 'down', 'down', 'up'], 905],\n   [['32.0', 900],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['32.0', 896],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]],\n [['regression: scenario 9',\n   ['C', ['up', 'down', 'down', 'up', 'down', 'up'], 445],\n   [['7.5', 455], ['7.0', 450], ['7.0', 450], ['7.5', 455], ['7.0', 450], ['7.5', 455]]],\n  ['regression: scenario 28',\n   ['C', ['up', 'down', 'down', 'up', 'down'], 905],\n   [['32.0', 900], ['31.5', 887], ['31.0', 878], ['31.5', 887], ['31.0', 878]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]]]\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":"d85cf2da8050d315fd59236cc14854ab200ad150ac319744e7c2aada459097ab","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(unit, presses, start_f10):\n    f10 = start_f10\n    out = []\n    for p in presses:\n        step = 1 if p == 'up' else -1\n        if unit == 'C':\n            c_half = (2 * (f10 - 320) + 9) // 18\n            f10 = 320 + (c_half + step) * 9\n        else:\n            f_whole = (f10 + 5) // 10\n            f10 = (f_whole + step) * 10\n        if unit == 'C':\n            c_half = (2 * (f10 - 320) + 9) // 18\n            out.append(['%d.%d' % (c_half // 2, 5 * (c_half % 2)), f10])\n        else:\n            out.append([str((f10 + 5) // 10), f10])\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]],\n  ['control: scenario 1',\n   ['F', ['down', 'down', 'up', 'up', 'up', 'down', 'down', 'up'], 716],\n   [['71', 710], ['70', 700], ['71', 710], ['72', 720], ['73', 730], ['72', 720], ['71', 710], ['72', 720]]],\n  ['control: scenario 2',\n   ['C', ['down', 'down', 'down', 'up', 'down', 'down', 'up'], 716],\n   [['21.5', 707],\n    ['21.0', 698],\n    ['20.5', 689],\n    ['21.0', 698],\n    ['20.5', 689],\n    ['20.0', 680],\n    ['20.5', 689]]]],\n [['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['regression: scenario 22',\n   ['C', ['down', 'down', 'up', 'down', 'down'], 445],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455], ['7.0', 450], ['7.0', 450]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]],\n  ['control: scenario 1',\n   ['F', ['down', 'down', 'up', 'up', 'down', 'down', 'down', 'up'], 652],\n   [['64', 640], ['63', 630], ['64', 640], ['65', 650], ['64', 640], ['63', 630], ['62', 620], ['63', 630]]]],\n [['regression: scenario 4',\n   ['C', ['down', 'up', 'down', 'down', 'down', 'down', 'down', 'up'], 445],\n   [['7.0', 450],\n    ['7.5', 455],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.5', 455]]],\n  ['regression: scenario 25',\n   ['C', ['down', 'down', 'down', 'up', 'down', 'up', 'up', 'up', 'down'], 905],\n   [['32.0', 896],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887],\n    ['32.0', 896],\n    ['32.0', 900],\n    ['31.5', 887]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]],\n [['regression: scenario 6',\n   ['C', ['up', 'up', 'down', 'down', 'down', 'down', 'down', 'down'], 905],\n   [['32.0', 900],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['30.5', 869],\n    ['30.0', 860],\n    ['29.5', 851],\n    ['29.0', 842]]],\n  ['regression: scenario 18',\n   ['C', ['up', 'up', 'down', 'up', 'up', 'down', 'down', 'up'], 905],\n   [['32.0', 900],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['32.0', 896],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]],\n [['regression: scenario 9',\n   ['C', ['up', 'down', 'down', 'up', 'down', 'up'], 445],\n   [['7.5', 455], ['7.0', 450], ['7.0', 450], ['7.5', 455], ['7.0', 450], ['7.5', 455]]],\n  ['regression: scenario 28',\n   ['C', ['up', 'down', 'down', 'up', 'down'], 905],\n   [['32.0', 900], ['31.5', 887], ['31.0', 878], ['31.5', 887], ['31.0', 878]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]]]\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"},"fixed":{"sha256":"4eb7718fa6937f8d35f2d1f2c25950f1e4c06eea5a395f68e0f7dfd08e306c52","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(unit, presses, start_f10):\n    f10 = start_f10\n    out = []\n    for p in presses:\n        step = 1 if p == 'up' else -1\n        if unit == 'C':\n            c_half = (2 * (f10 - 320) + 9) // 18\n            f10 = 320 + (c_half + step) * 9\n        else:\n            f_whole = (f10 + 5) // 10\n            f10 = (f_whole + step) * 10\n        f10 = max(450, min(900, f10))\n        if unit == 'C':\n            c_half = (2 * (f10 - 320) + 9) // 18\n            out.append(['%d.%d' % (c_half // 2, 5 * (c_half % 2)), f10])\n        else:\n            out.append([str((f10 + 5) // 10), f10])\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]],\n  ['control: scenario 1',\n   ['F', ['down', 'down', 'up', 'up', 'up', 'down', 'down', 'up'], 716],\n   [['71', 710], ['70', 700], ['71', 710], ['72', 720], ['73', 730], ['72', 720], ['71', 710], ['72', 720]]],\n  ['control: scenario 2',\n   ['C', ['down', 'down', 'down', 'up', 'down', 'down', 'up'], 716],\n   [['21.5', 707],\n    ['21.0', 698],\n    ['20.5', 689],\n    ['21.0', 698],\n    ['20.5', 689],\n    ['20.0', 680],\n    ['20.5', 689]]]],\n [['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['regression: scenario 22',\n   ['C', ['down', 'down', 'up', 'down', 'down'], 445],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455], ['7.0', 450], ['7.0', 450]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]],\n  ['control: scenario 1',\n   ['F', ['down', 'down', 'up', 'up', 'down', 'down', 'down', 'up'], 652],\n   [['64', 640], ['63', 630], ['64', 640], ['65', 650], ['64', 640], ['63', 630], ['62', 620], ['63', 630]]]],\n [['regression: scenario 4',\n   ['C', ['down', 'up', 'down', 'down', 'down', 'down', 'down', 'up'], 445],\n   [['7.0', 450],\n    ['7.5', 455],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.0', 450],\n    ['7.5', 455]]],\n  ['regression: scenario 25',\n   ['C', ['down', 'down', 'down', 'up', 'down', 'up', 'up', 'up', 'down'], 905],\n   [['32.0', 896],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887],\n    ['32.0', 896],\n    ['32.0', 900],\n    ['31.5', 887]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]],\n [['regression: scenario 6',\n   ['C', ['up', 'up', 'down', 'down', 'down', 'down', 'down', 'down'], 905],\n   [['32.0', 900],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['30.5', 869],\n    ['30.0', 860],\n    ['29.5', 851],\n    ['29.0', 842]]],\n  ['regression: scenario 18',\n   ['C', ['up', 'up', 'down', 'up', 'up', 'down', 'down', 'up'], 905],\n   [['32.0', 900],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['32.0', 896],\n    ['32.0', 900],\n    ['31.5', 887],\n    ['31.0', 878],\n    ['31.5', 887]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]],\n [['regression: scenario 9',\n   ['C', ['up', 'down', 'down', 'up', 'down', 'up'], 445],\n   [['7.5', 455], ['7.0', 450], ['7.0', 450], ['7.5', 455], ['7.0', 450], ['7.5', 455]]],\n  ['regression: scenario 28',\n   ['C', ['up', 'down', 'down', 'up', 'down'], 905],\n   [['32.0', 900], ['31.5', 887], ['31.0', 878], ['31.5', 887], ['31.0', 878]]],\n  ['control: celsius steps', ['C', ['up', 'up', 'down'], 720], [['22.5', 725], ['23.0', 734], ['22.5', 725]]],\n  ['control: fahrenheit half value',\n   ['F', ['up', 'down', 'down'], 725],\n   [['74', 740], ['73', 730], ['72', 720]]],\n  ['regression: upper clamp', ['F', ['up'], 895], [['90', 900]]],\n  ['control: celsius off-grid start', ['C', ['down', 'up'], 716], [['21.5', 707], ['22.0', 716]]],\n  ['regression: celsius lower clamp',\n   ['C', ['down', 'down', 'up'], 452],\n   [['7.0', 450], ['7.0', 450], ['7.5', 455]]],\n  ['control: celsius half-step display', ['C', ['up'], 707], [['22.0', 716]]]]]\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-keypad-units-clamp-per-unit","generated_at":"2026-09-29T14:51:46.480091+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.","repair":"Clamp the stored value after every press, in both units.","root_cause":"The clamp is missing after the press.","sha256":"92140d7feaa9237a1a80368055376db383230e8a1f98ded7cead44623f171ccc","title":"Setpoint limits are only enforced in one display unit · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":45.618,"exit_code":1,"observations":[{"actual":[["90",900]],"check":"regression: upper clamp","expected":[["90",900]],"passed":true},{"actual":[["7.0",446],["6.5",437],["7.0",446]],"check":"regression: celsius lower clamp","expected":[["7.0",450],["7.0",450],["7.5",455]],"passed":false},{"actual":[["22.5",725],["23.0",734],["22.5",725]],"check":"control: celsius steps","expected":[["22.5",725],["23.0",734],["22.5",725]],"passed":true},{"actual":[["74",740],["73",730],["72",720]],"check":"control: fahrenheit half value","expected":[["74",740],["73",730],["72",720]],"passed":true},{"actual":[["21.5",707],["22.0",716]],"check":"control: celsius off-grid start","expected":[["21.5",707],["22.0",716]],"passed":true},{"actual":[["22.0",716]],"check":"control: celsius half-step display","expected":[["22.0",716]],"passed":true},{"actual":[["71",710],["70",700],["71",710],["72",720],["73",730],["72",720],["71",710],["72",720]],"check":"control: scenario 1","expected":[["71",710],["70",700],["71",710],["72",720],["73",730],["72",720],["71",710],["72",720]],"passed":true},{"actual":[["21.5",707],["21.0",698],["20.5",689],["21.0",698],["20.5",689],["20.0",680],["20.5",689]],"check":"control: scenario 2","expected":[["21.5",707],["21.0",698],["20.5",689],["21.0",698],["20.5",689],["20.0",680],["20.5",689]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: upper clamp\", \"actual\": [[\"90\", 900]], \"expected\": [[\"90\", 900]], \"passed\": true}, {\"check\": \"regression: celsius lower clamp\", \"actual\": [[\"7.0\", 446], [\"6.5\", 437], [\"7.0\", 446]], \"expected\": [[\"7.0\", 450], [\"7.0\", 450], [\"7.5\", 455]], \"passed\": false}, {\"check\": \"control: celsius steps\", \"actual\": [[\"22.5\", 725], [\"23.0\", 734], [\"22.5\", 725]], \"expected\": [[\"22.5\", 725], [\"23.0\", 734], [\"22.5\", 725]], \"passed\": true}, {\"check\": \"control: fahrenheit half value\", \"actual\": [[\"74\", 740], [\"73\", 730], [\"72\", 720]], \"expected\": [[\"74\", 740], [\"73\", 730], [\"72\", 720]], \"passed\": true}, {\"check\": \"control: celsius off-grid start\", \"actual\": [[\"21.5\", 707], [\"22.0\", 716]], \"expected\": [[\"21.5\", 707], [\"22.0\", 716]], \"passed\": true}, {\"check\": \"control: celsius half-step display\", \"actual\": [[\"22.0\", 716]], \"expected\": [[\"22.0\", 716]], \"passed\": true}, {\"check\": \"control: scenario 1\", \"actual\": [[\"71\", 710], [\"70\", 700], [\"71\", 710], [\"72\", 720], [\"73\", 730], [\"72\", 720], [\"71\", 710], [\"72\", 720]], \"expected\": [[\"71\", 710], [\"70\", 700], [\"71\", 710], [\"72\", 720], [\"73\", 730], [\"72\", 720], [\"71\", 710], [\"72\", 720]], \"passed\": true}, {\"check\": \"control: scenario 2\", \"actual\": [[\"21.5\", 707], [\"21.0\", 698], [\"20.5\", 689], [\"21.0\", 698], [\"20.5\", 689], [\"20.0\", 680], [\"20.5\", 689]], \"expected\": [[\"21.5\", 707], [\"21.0\", 698], [\"20.5\", 689], [\"21.0\", 698], [\"20.5\", 689], [\"20.0\", 680], [\"20.5\", 689]], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":44.728,"exit_code":1,"observations":[{"actual":[["91",910]],"check":"regression: upper clamp","expected":[["90",900]],"passed":false},{"actual":[["7.0",446],["6.5",437],["7.0",446]],"check":"regression: celsius lower clamp","expected":[["7.0",450],["7.0",450],["7.5",455]],"passed":false},{"actual":[["22.5",725],["23.0",734],["22.5",725]],"check":"control: celsius steps","expected":[["22.5",725],["23.0",734],["22.5",725]],"passed":true},{"actual":[["74",740],["73",730],["72",720]],"check":"control: fahrenheit half value","expected":[["74",740],["73",730],["72",720]],"passed":true},{"actual":[["21.5",707],["22.0",716]],"check":"control: celsius off-grid start","expected":[["21.5",707],["22.0",716]],"passed":true},{"actual":[["22.0",716]],"check":"control: celsius half-step display","expected":[["22.0",716]],"passed":true},{"actual":[["71",710],["70",700],["71",710],["72",720],["73",730],["72",720],["71",710],["72",720]],"check":"control: scenario 1","expected":[["71",710],["70",700],["71",710],["72",720],["73",730],["72",720],["71",710],["72",720]],"passed":true},{"actual":[["21.5",707],["21.0",698],["20.5",689],["21.0",698],["20.5",689],["20.0",680],["20.5",689]],"check":"control: scenario 2","expected":[["21.5",707],["21.0",698],["20.5",689],["21.0",698],["20.5",689],["20.0",680],["20.5",689]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: upper clamp\", \"actual\": [[\"91\", 910]], \"expected\": [[\"90\", 900]], \"passed\": false}, {\"check\": \"regression: celsius lower clamp\", \"actual\": [[\"7.0\", 446], [\"6.5\", 437], [\"7.0\", 446]], \"expected\": [[\"7.0\", 450], [\"7.0\", 450], [\"7.5\", 455]], \"passed\": false}, {\"check\": \"control: celsius steps\", \"actual\": [[\"22.5\", 725], [\"23.0\", 734], [\"22.5\", 725]], \"expected\": [[\"22.5\", 725], [\"23.0\", 734], [\"22.5\", 725]], \"passed\": true}, {\"check\": \"control: fahrenheit half value\", \"actual\": [[\"74\", 740], [\"73\", 730], [\"72\", 720]], \"expected\": [[\"74\", 740], [\"73\", 730], [\"72\", 720]], \"passed\": true}, {\"check\": \"control: celsius off-grid start\", \"actual\": [[\"21.5\", 707], [\"22.0\", 716]], \"expected\": [[\"21.5\", 707], [\"22.0\", 716]], \"passed\": true}, {\"check\": \"control: celsius half-step display\", \"actual\": [[\"22.0\", 716]], \"expected\": [[\"22.0\", 716]], \"passed\": true}, {\"check\": \"control: scenario 1\", \"actual\": [[\"71\", 710], [\"70\", 700], [\"71\", 710], [\"72\", 720], [\"73\", 730], [\"72\", 720], [\"71\", 710], [\"72\", 720]], \"expected\": [[\"71\", 710], [\"70\", 700], [\"71\", 710], [\"72\", 720], [\"73\", 730], [\"72\", 720], [\"71\", 710], [\"72\", 720]], \"passed\": true}, {\"check\": \"control: scenario 2\", \"actual\": [[\"21.5\", 707], [\"21.0\", 698], [\"20.5\", 689], [\"21.0\", 698], [\"20.5\", 689], [\"20.0\", 680], [\"20.5\", 689]], \"expected\": [[\"21.5\", 707], [\"21.0\", 698], [\"20.5\", 689], [\"21.0\", 698], [\"20.5\", 689], [\"20.0\", 680], [\"20.5\", 689]], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":41.811,"exit_code":0,"observations":[{"actual":[["90",900]],"check":"regression: upper clamp","expected":[["90",900]],"passed":true},{"actual":[["7.0",450],["7.0",450],["7.5",455]],"check":"regression: celsius lower clamp","expected":[["7.0",450],["7.0",450],["7.5",455]],"passed":true},{"actual":[["22.5",725],["23.0",734],["22.5",725]],"check":"control: celsius steps","expected":[["22.5",725],["23.0",734],["22.5",725]],"passed":true},{"actual":[["74",740],["73",730],["72",720]],"check":"control: fahrenheit half value","expected":[["74",740],["73",730],["72",720]],"passed":true},{"actual":[["21.5",707],["22.0",716]],"check":"control: celsius off-grid start","expected":[["21.5",707],["22.0",716]],"passed":true},{"actual":[["22.0",716]],"check":"control: celsius half-step display","expected":[["22.0",716]],"passed":true},{"actual":[["71",710],["70",700],["71",710],["72",720],["73",730],["72",720],["71",710],["72",720]],"check":"control: scenario 1","expected":[["71",710],["70",700],["71",710],["72",720],["73",730],["72",720],["71",710],["72",720]],"passed":true},{"actual":[["21.5",707],["21.0",698],["20.5",689],["21.0",698],["20.5",689],["20.0",680],["20.5",689]],"check":"control: scenario 2","expected":[["21.5",707],["21.0",698],["20.5",689],["21.0",698],["20.5",689],["20.0",680],["20.5",689]],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: upper clamp\", \"actual\": [[\"90\", 900]], \"expected\": [[\"90\", 900]], \"passed\": true}, {\"check\": \"regression: celsius lower clamp\", \"actual\": [[\"7.0\", 450], [\"7.0\", 450], [\"7.5\", 455]], \"expected\": [[\"7.0\", 450], [\"7.0\", 450], [\"7.5\", 455]], \"passed\": true}, {\"check\": \"control: celsius steps\", \"actual\": [[\"22.5\", 725], [\"23.0\", 734], [\"22.5\", 725]], \"expected\": [[\"22.5\", 725], [\"23.0\", 734], [\"22.5\", 725]], \"passed\": true}, {\"check\": \"control: fahrenheit half value\", \"actual\": [[\"74\", 740], [\"73\", 730], [\"72\", 720]], \"expected\": [[\"74\", 740], [\"73\", 730], [\"72\", 720]], \"passed\": true}, {\"check\": \"control: celsius off-grid start\", \"actual\": [[\"21.5\", 707], [\"22.0\", 716]], \"expected\": [[\"21.5\", 707], [\"22.0\", 716]], \"passed\": true}, {\"check\": \"control: celsius half-step display\", \"actual\": [[\"22.0\", 716]], \"expected\": [[\"22.0\", 716]], \"passed\": true}, {\"check\": \"control: scenario 1\", \"actual\": [[\"71\", 710], [\"70\", 700], [\"71\", 710], [\"72\", 720], [\"73\", 730], [\"72\", 720], [\"71\", 710], [\"72\", 720]], \"expected\": [[\"71\", 710], [\"70\", 700], [\"71\", 710], [\"72\", 720], [\"73\", 730], [\"72\", 720], [\"71\", 710], [\"72\", 720]], \"passed\": true}, {\"check\": \"control: scenario 2\", \"actual\": [[\"21.5\", 707], [\"21.0\", 698], [\"20.5\", 689], [\"21.0\", 698], [\"20.5\", 689], [\"20.0\", 680], [\"20.5\", 689]], \"expected\": [[\"21.5\", 707], [\"21.0\", 698], [\"20.5\", 689], [\"21.0\", 698], [\"20.5\", 689], [\"20.0\", 680], [\"20.5\", 689]], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}