FAILURE MAP
← Case archive

FA-92466 / HVAC thermostat control / Open access

Schedule event does not apply at its own start minute · case 01

At exactly the programmed time the thermostat still shows the previous period.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The lookup takes events strictly before the query time.

VERIFIED REPAIR

An event is active from its own minute (et <= t).

Unsuccessful approach: Special-casing midnight events leaves other exact-minute changes late.

Case contract

Programmable thermostat weekly schedule. schedule is an unordered list of [day 0=Monday..6, minute_of_day, setpoint]; queries are [day, minute]. The active setpoint is that of the latest event at or before the query time within the week; if none, the last event of the week carries over from the previous week. Return the active setpoint per query.

Why this case matters

Residential and light-commercial thermostats make these decisions sample by sample; each defect changes equipment calls in a way that shows up as short cycling, comfort complaints or equipment stress.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(schedule, queries):
    events = sorted((d * 1440 + m, sp) for d, m, sp in schedule)
    out = []
    for d, m in queries:
        t = d * 1440 + m
        current = events[-1][1]
        for et, sp in events:
            if et < t:
                current = sp
            else:
                break
        out.append(current)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[3, 1140, 720], [5, 1170, 700], [5, 510, 600]],
    [[3, 1242], [2, 953], [2, 1283], [4, 1029], [3, 1140], [5, 1170]]],
   [720, 700, 700, 720, 720, 700]],
  ['control: scenario 2',
   [[[3, 1200, 650], [1, 690, 650]],
    [[1, 1355], [2, 28], [0, 994], [6, 594], [4, 142], [3, 1098], [3, 630], [3, 1200], [1, 690]]],
   [650, 650, 650, 650, 650, 650, 650, 650, 650]],
  ['regression: scenario 3',
   [[[2, 480, 600], [6, 900, 720], [3, 750, 650]],
    [[5, 771], [4, 147], [0, 469], [1, 1048], [0, 854], [0, 1005], [2, 379], [2, 480], [6, 900]]],
   [650, 650, 720, 720, 720, 720, 720, 600, 720]],
  ['regression: scenario 4',
   [[[5, 420, 720], [2, 420, 650], [4, 0, 680], [6, 750, 650], [4, 1170, 680], [4, 90, 680], [4, 150, 600]],
    [[4, 703], [5, 1293], [2, 238], [6, 1060], [2, 806], [5, 420], [2, 420]]],
   [600, 720, 650, 650, 650, 720, 650]]],
 [['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['regression: scenario 1',
   [[[2, 240, 600], [1, 810, 620], [4, 1320, 620], [5, 690, 680], [0, 960, 720], [5, 1230, 680]],
    [[3, 1330], [0, 340], [5, 693], [6, 1037], [2, 240], [1, 810]]],
   [600, 680, 680, 680, 600, 620]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 2',
   [[[0, 360, 600], [2, 210, 720], [2, 1200, 620], [5, 330, 680], [6, 1410, 680], [4, 0, 620], [1, 390, 720]],
    [[1, 1030], [0, 695], [3, 1138], [3, 1242], [0, 264], [0, 360], [2, 210]]],
   [720, 600, 620, 620, 680, 600, 720]],
  ['regression: scenario 3',
   [[[2, 1290, 720], [1, 300, 600], [4, 900, 700], [4, 960, 650], [5, 870, 650]],
    [[4, 157], [3, 57], [4, 1382], [5, 1288], [2, 1290], [1, 300]]],
   [720, 720, 650, 650, 720, 600]],
  ['regression: scenario 4',
   [[[2, 810, 700], [3, 180, 700], [2, 1260, 600], [5, 960, 720], [3, 1230, 700]],
    [[1, 1267], [2, 448], [6, 679], [6, 778], [1, 1017], [0, 371], [2, 810], [3, 180]]],
   [720, 720, 720, 720, 720, 720, 700, 700]]],
 [['regression: scenario 1',
   [[[2, 870, 650], [2, 1260, 700], [0, 1050, 600]],
    [[6, 998], [2, 333], [4, 1015], [1, 556], [2, 389], [5, 846], [4, 1066], [3, 53], [2, 870], [2, 1260]]],
   [700, 600, 700, 600, 600, 700, 700, 700, 650, 700]],
  ['regression: scenario 2',
   [[[5, 60, 600], [0, 810, 680]], [[3, 524], [2, 1316], [2, 829], [1, 1320], [5, 60], [0, 810]]],
   [680, 680, 680, 680, 600, 680]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 3',
   [[[5, 390, 700], [1, 990, 600], [5, 1260, 720], [1, 720, 720], [0, 840, 650], [0, 330, 700], [2, 0, 600]],
    [[3, 1359], [2, 341], [5, 1109], [1, 674], [5, 884], [6, 597], [6, 156], [6, 1198], [5, 390], [1, 990]]],
   [600, 600, 700, 650, 700, 720, 720, 720, 700, 600]],
  ['regression: scenario 4',
   [[[1, 960, 650], [0, 1080, 600], [3, 60, 620], [3, 720, 600], [5, 180, 600], [5, 420, 680]],
    [[5, 1036], [6, 745], [3, 680], [3, 505], [1, 960], [0, 1080]]],
   [680, 680, 620, 620, 650, 600]]],
 [['regression: scenario 2',
   [[[0, 450, 600],
     [2, 480, 600],
     [0, 510, 720],
     [4, 690, 700],
     [1, 1020, 680],
     [6, 330, 620],
     [2, 120, 720]],
    [[1, 971], [4, 1250], [6, 999], [5, 1034], [4, 1097], [1, 624], [1, 447], [0, 450], [2, 480]]],
   [720, 700, 620, 700, 700, 720, 720, 600, 600]],
  ['regression: scenario 3',
   [[[3, 1260, 720], [2, 450, 680]],
    [[3, 594], [1, 866], [2, 623], [6, 394], [4, 309], [4, 881], [3, 1260], [2, 450]]],
   [680, 720, 680, 720, 720, 720, 720, 680]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[0, 1050, 720], [6, 0, 650]],
    [[3, 1304], [4, 593], [3, 411], [0, 1396], [2, 508], [2, 1205], [1, 360], [5, 1314], [0, 1050], [6, 0]]],
   [720, 720, 720, 720, 720, 720, 720, 720, 720, 650]],
  ['regression: scenario 4',
   [[[5, 1170, 600], [3, 1200, 720], [6, 480, 700], [1, 1380, 700]],
    [[2, 1118], [1, 1160], [2, 36], [2, 1281], [3, 262], [5, 1170], [3, 1200]]],
   [700, 700, 700, 700, 700, 600, 720]]],
 [['regression: scenario 3',
   [[[1, 30, 650],
     [3, 0, 620],
     [3, 300, 700],
     [5, 1050, 720],
     [3, 1410, 700],
     [4, 1380, 680],
     [4, 240, 700],
     [4, 1350, 620]],
    [[0, 1419], [0, 281], [0, 1177], [3, 645], [6, 230], [0, 799], [1, 30], [3, 0]]],
   [720, 720, 720, 700, 720, 720, 650, 620]],
  ['regression: scenario 4',
   [[[1, 1050, 700],
     [5, 1080, 700],
     [4, 1350, 680],
     [2, 720, 680],
     [0, 840, 720],
     [5, 1260, 600],
     [2, 750, 650],
     [0, 540, 600]],
    [[6, 269], [5, 893], [0, 381], [1, 1193], [4, 963], [5, 504], [3, 819], [1, 1050], [5, 1080]]],
   [600, 680, 600, 700, 650, 680, 650, 700, 700]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[5, 1020, 600], [4, 900, 620], [5, 510, 680], [1, 1200, 680]],
    [[4, 860], [4, 862], [4, 1233], [4, 668], [4, 180], [0, 208], [2, 1192], [5, 1020], [4, 900]]],
   [680, 680, 620, 680, 680, 600, 680, 600, 620]],
  ['regression: scenario 2',
   [[[3, 330, 700],
     [1, 960, 700],
     [2, 540, 650],
     [3, 810, 600],
     [5, 1080, 700],
     [1, 300, 680],
     [6, 1020, 650]],
    [[6, 811], [3, 629], [0, 1103], [3, 1144], [4, 229], [3, 330], [1, 960]]],
   [700, 700, 650, 600, 600, 700, 700]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: week wrap and exact times[640, 640, 620, 700, 700, 640][640, 700, 620, 700, 640, 640]Failed
regression: unsorted entries[700, 640, 680, 640][700, 640, 680, 680]Failed
control: late evening event[600, 600, 690][600, 600, 690]Passed
control: tuesday first event[680, 620, 680][680, 620, 680]Passed
regression: scenario 1[720, 700, 700, 720, 700, 600][720, 700, 700, 720, 720, 700]Failed
control: scenario 2[650, 650, 650, 650, 650, 650, 650, 650, 650][650, 650, 650, 650, 650, 650, 650, 650, 650]Passed
regression: scenario 3[650, 650, 720, 720, 720, 720, 720, 720, 650][650, 650, 720, 720, 720, 720, 720, 600, 720]Failed
regression: scenario 4[600, 720, 650, 650, 650, 680, 650][600, 720, 650, 650, 650, 720, 650]Failed

SHA-256 / e3206525c512f1dc851ee8e9d411b9cdbf2160c146669e3fd17bb214f9dc9c4a

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(schedule, queries):
    events = sorted((d * 1440 + m, sp) for d, m, sp in schedule)
    out = []
    for d, m in queries:
        t = d * 1440 + m
        current = events[-1][1]
        for et, sp in events:
            if et < t or (et == t and et % 1440 == 0):
                current = sp
            else:
                break
        out.append(current)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[3, 1140, 720], [5, 1170, 700], [5, 510, 600]],
    [[3, 1242], [2, 953], [2, 1283], [4, 1029], [3, 1140], [5, 1170]]],
   [720, 700, 700, 720, 720, 700]],
  ['control: scenario 2',
   [[[3, 1200, 650], [1, 690, 650]],
    [[1, 1355], [2, 28], [0, 994], [6, 594], [4, 142], [3, 1098], [3, 630], [3, 1200], [1, 690]]],
   [650, 650, 650, 650, 650, 650, 650, 650, 650]],
  ['regression: scenario 3',
   [[[2, 480, 600], [6, 900, 720], [3, 750, 650]],
    [[5, 771], [4, 147], [0, 469], [1, 1048], [0, 854], [0, 1005], [2, 379], [2, 480], [6, 900]]],
   [650, 650, 720, 720, 720, 720, 720, 600, 720]],
  ['regression: scenario 4',
   [[[5, 420, 720], [2, 420, 650], [4, 0, 680], [6, 750, 650], [4, 1170, 680], [4, 90, 680], [4, 150, 600]],
    [[4, 703], [5, 1293], [2, 238], [6, 1060], [2, 806], [5, 420], [2, 420]]],
   [600, 720, 650, 650, 650, 720, 650]]],
 [['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['regression: scenario 1',
   [[[2, 240, 600], [1, 810, 620], [4, 1320, 620], [5, 690, 680], [0, 960, 720], [5, 1230, 680]],
    [[3, 1330], [0, 340], [5, 693], [6, 1037], [2, 240], [1, 810]]],
   [600, 680, 680, 680, 600, 620]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 2',
   [[[0, 360, 600], [2, 210, 720], [2, 1200, 620], [5, 330, 680], [6, 1410, 680], [4, 0, 620], [1, 390, 720]],
    [[1, 1030], [0, 695], [3, 1138], [3, 1242], [0, 264], [0, 360], [2, 210]]],
   [720, 600, 620, 620, 680, 600, 720]],
  ['regression: scenario 3',
   [[[2, 1290, 720], [1, 300, 600], [4, 900, 700], [4, 960, 650], [5, 870, 650]],
    [[4, 157], [3, 57], [4, 1382], [5, 1288], [2, 1290], [1, 300]]],
   [720, 720, 650, 650, 720, 600]],
  ['regression: scenario 4',
   [[[2, 810, 700], [3, 180, 700], [2, 1260, 600], [5, 960, 720], [3, 1230, 700]],
    [[1, 1267], [2, 448], [6, 679], [6, 778], [1, 1017], [0, 371], [2, 810], [3, 180]]],
   [720, 720, 720, 720, 720, 720, 700, 700]]],
 [['regression: scenario 1',
   [[[2, 870, 650], [2, 1260, 700], [0, 1050, 600]],
    [[6, 998], [2, 333], [4, 1015], [1, 556], [2, 389], [5, 846], [4, 1066], [3, 53], [2, 870], [2, 1260]]],
   [700, 600, 700, 600, 600, 700, 700, 700, 650, 700]],
  ['regression: scenario 2',
   [[[5, 60, 600], [0, 810, 680]], [[3, 524], [2, 1316], [2, 829], [1, 1320], [5, 60], [0, 810]]],
   [680, 680, 680, 680, 600, 680]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 3',
   [[[5, 390, 700], [1, 990, 600], [5, 1260, 720], [1, 720, 720], [0, 840, 650], [0, 330, 700], [2, 0, 600]],
    [[3, 1359], [2, 341], [5, 1109], [1, 674], [5, 884], [6, 597], [6, 156], [6, 1198], [5, 390], [1, 990]]],
   [600, 600, 700, 650, 700, 720, 720, 720, 700, 600]],
  ['regression: scenario 4',
   [[[1, 960, 650], [0, 1080, 600], [3, 60, 620], [3, 720, 600], [5, 180, 600], [5, 420, 680]],
    [[5, 1036], [6, 745], [3, 680], [3, 505], [1, 960], [0, 1080]]],
   [680, 680, 620, 620, 650, 600]]],
 [['regression: scenario 2',
   [[[0, 450, 600],
     [2, 480, 600],
     [0, 510, 720],
     [4, 690, 700],
     [1, 1020, 680],
     [6, 330, 620],
     [2, 120, 720]],
    [[1, 971], [4, 1250], [6, 999], [5, 1034], [4, 1097], [1, 624], [1, 447], [0, 450], [2, 480]]],
   [720, 700, 620, 700, 700, 720, 720, 600, 600]],
  ['regression: scenario 3',
   [[[3, 1260, 720], [2, 450, 680]],
    [[3, 594], [1, 866], [2, 623], [6, 394], [4, 309], [4, 881], [3, 1260], [2, 450]]],
   [680, 720, 680, 720, 720, 720, 720, 680]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[0, 1050, 720], [6, 0, 650]],
    [[3, 1304], [4, 593], [3, 411], [0, 1396], [2, 508], [2, 1205], [1, 360], [5, 1314], [0, 1050], [6, 0]]],
   [720, 720, 720, 720, 720, 720, 720, 720, 720, 650]],
  ['regression: scenario 4',
   [[[5, 1170, 600], [3, 1200, 720], [6, 480, 700], [1, 1380, 700]],
    [[2, 1118], [1, 1160], [2, 36], [2, 1281], [3, 262], [5, 1170], [3, 1200]]],
   [700, 700, 700, 700, 700, 600, 720]]],
 [['regression: scenario 3',
   [[[1, 30, 650],
     [3, 0, 620],
     [3, 300, 700],
     [5, 1050, 720],
     [3, 1410, 700],
     [4, 1380, 680],
     [4, 240, 700],
     [4, 1350, 620]],
    [[0, 1419], [0, 281], [0, 1177], [3, 645], [6, 230], [0, 799], [1, 30], [3, 0]]],
   [720, 720, 720, 700, 720, 720, 650, 620]],
  ['regression: scenario 4',
   [[[1, 1050, 700],
     [5, 1080, 700],
     [4, 1350, 680],
     [2, 720, 680],
     [0, 840, 720],
     [5, 1260, 600],
     [2, 750, 650],
     [0, 540, 600]],
    [[6, 269], [5, 893], [0, 381], [1, 1193], [4, 963], [5, 504], [3, 819], [1, 1050], [5, 1080]]],
   [600, 680, 600, 700, 650, 680, 650, 700, 700]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[5, 1020, 600], [4, 900, 620], [5, 510, 680], [1, 1200, 680]],
    [[4, 860], [4, 862], [4, 1233], [4, 668], [4, 180], [0, 208], [2, 1192], [5, 1020], [4, 900]]],
   [680, 680, 620, 680, 680, 600, 680, 600, 620]],
  ['regression: scenario 2',
   [[[3, 330, 700],
     [1, 960, 700],
     [2, 540, 650],
     [3, 810, 600],
     [5, 1080, 700],
     [1, 300, 680],
     [6, 1020, 650]],
    [[6, 811], [3, 629], [0, 1103], [3, 1144], [4, 229], [3, 330], [1, 960]]],
   [700, 700, 650, 600, 600, 700, 700]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: week wrap and exact times[640, 640, 620, 700, 700, 640][640, 700, 620, 700, 640, 640]Failed
regression: unsorted entries[700, 640, 680, 640][700, 640, 680, 680]Failed
control: late evening event[600, 600, 690][600, 600, 690]Passed
control: tuesday first event[680, 620, 680][680, 620, 680]Passed
regression: scenario 1[720, 700, 700, 720, 700, 600][720, 700, 700, 720, 720, 700]Failed
control: scenario 2[650, 650, 650, 650, 650, 650, 650, 650, 650][650, 650, 650, 650, 650, 650, 650, 650, 650]Passed
regression: scenario 3[650, 650, 720, 720, 720, 720, 720, 720, 650][650, 650, 720, 720, 720, 720, 720, 600, 720]Failed
regression: scenario 4[600, 720, 650, 650, 650, 680, 650][600, 720, 650, 650, 650, 720, 650]Failed

SHA-256 / 449a823f436d87dc6c064dbeb478826aba9c14b14a21349c91f64723fc1a46ed

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(schedule, queries):
    events = sorted((d * 1440 + m, sp) for d, m, sp in schedule)
    out = []
    for d, m in queries:
        t = d * 1440 + m
        current = events[-1][1]
        for et, sp in events:
            if et <= t:
                current = sp
            else:
                break
        out.append(current)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[3, 1140, 720], [5, 1170, 700], [5, 510, 600]],
    [[3, 1242], [2, 953], [2, 1283], [4, 1029], [3, 1140], [5, 1170]]],
   [720, 700, 700, 720, 720, 700]],
  ['control: scenario 2',
   [[[3, 1200, 650], [1, 690, 650]],
    [[1, 1355], [2, 28], [0, 994], [6, 594], [4, 142], [3, 1098], [3, 630], [3, 1200], [1, 690]]],
   [650, 650, 650, 650, 650, 650, 650, 650, 650]],
  ['regression: scenario 3',
   [[[2, 480, 600], [6, 900, 720], [3, 750, 650]],
    [[5, 771], [4, 147], [0, 469], [1, 1048], [0, 854], [0, 1005], [2, 379], [2, 480], [6, 900]]],
   [650, 650, 720, 720, 720, 720, 720, 600, 720]],
  ['regression: scenario 4',
   [[[5, 420, 720], [2, 420, 650], [4, 0, 680], [6, 750, 650], [4, 1170, 680], [4, 90, 680], [4, 150, 600]],
    [[4, 703], [5, 1293], [2, 238], [6, 1060], [2, 806], [5, 420], [2, 420]]],
   [600, 720, 650, 650, 650, 720, 650]]],
 [['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['regression: scenario 1',
   [[[2, 240, 600], [1, 810, 620], [4, 1320, 620], [5, 690, 680], [0, 960, 720], [5, 1230, 680]],
    [[3, 1330], [0, 340], [5, 693], [6, 1037], [2, 240], [1, 810]]],
   [600, 680, 680, 680, 600, 620]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 2',
   [[[0, 360, 600], [2, 210, 720], [2, 1200, 620], [5, 330, 680], [6, 1410, 680], [4, 0, 620], [1, 390, 720]],
    [[1, 1030], [0, 695], [3, 1138], [3, 1242], [0, 264], [0, 360], [2, 210]]],
   [720, 600, 620, 620, 680, 600, 720]],
  ['regression: scenario 3',
   [[[2, 1290, 720], [1, 300, 600], [4, 900, 700], [4, 960, 650], [5, 870, 650]],
    [[4, 157], [3, 57], [4, 1382], [5, 1288], [2, 1290], [1, 300]]],
   [720, 720, 650, 650, 720, 600]],
  ['regression: scenario 4',
   [[[2, 810, 700], [3, 180, 700], [2, 1260, 600], [5, 960, 720], [3, 1230, 700]],
    [[1, 1267], [2, 448], [6, 679], [6, 778], [1, 1017], [0, 371], [2, 810], [3, 180]]],
   [720, 720, 720, 720, 720, 720, 700, 700]]],
 [['regression: scenario 1',
   [[[2, 870, 650], [2, 1260, 700], [0, 1050, 600]],
    [[6, 998], [2, 333], [4, 1015], [1, 556], [2, 389], [5, 846], [4, 1066], [3, 53], [2, 870], [2, 1260]]],
   [700, 600, 700, 600, 600, 700, 700, 700, 650, 700]],
  ['regression: scenario 2',
   [[[5, 60, 600], [0, 810, 680]], [[3, 524], [2, 1316], [2, 829], [1, 1320], [5, 60], [0, 810]]],
   [680, 680, 680, 680, 600, 680]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 3',
   [[[5, 390, 700], [1, 990, 600], [5, 1260, 720], [1, 720, 720], [0, 840, 650], [0, 330, 700], [2, 0, 600]],
    [[3, 1359], [2, 341], [5, 1109], [1, 674], [5, 884], [6, 597], [6, 156], [6, 1198], [5, 390], [1, 990]]],
   [600, 600, 700, 650, 700, 720, 720, 720, 700, 600]],
  ['regression: scenario 4',
   [[[1, 960, 650], [0, 1080, 600], [3, 60, 620], [3, 720, 600], [5, 180, 600], [5, 420, 680]],
    [[5, 1036], [6, 745], [3, 680], [3, 505], [1, 960], [0, 1080]]],
   [680, 680, 620, 620, 650, 600]]],
 [['regression: scenario 2',
   [[[0, 450, 600],
     [2, 480, 600],
     [0, 510, 720],
     [4, 690, 700],
     [1, 1020, 680],
     [6, 330, 620],
     [2, 120, 720]],
    [[1, 971], [4, 1250], [6, 999], [5, 1034], [4, 1097], [1, 624], [1, 447], [0, 450], [2, 480]]],
   [720, 700, 620, 700, 700, 720, 720, 600, 600]],
  ['regression: scenario 3',
   [[[3, 1260, 720], [2, 450, 680]],
    [[3, 594], [1, 866], [2, 623], [6, 394], [4, 309], [4, 881], [3, 1260], [2, 450]]],
   [680, 720, 680, 720, 720, 720, 720, 680]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[0, 1050, 720], [6, 0, 650]],
    [[3, 1304], [4, 593], [3, 411], [0, 1396], [2, 508], [2, 1205], [1, 360], [5, 1314], [0, 1050], [6, 0]]],
   [720, 720, 720, 720, 720, 720, 720, 720, 720, 650]],
  ['regression: scenario 4',
   [[[5, 1170, 600], [3, 1200, 720], [6, 480, 700], [1, 1380, 700]],
    [[2, 1118], [1, 1160], [2, 36], [2, 1281], [3, 262], [5, 1170], [3, 1200]]],
   [700, 700, 700, 700, 700, 600, 720]]],
 [['regression: scenario 3',
   [[[1, 30, 650],
     [3, 0, 620],
     [3, 300, 700],
     [5, 1050, 720],
     [3, 1410, 700],
     [4, 1380, 680],
     [4, 240, 700],
     [4, 1350, 620]],
    [[0, 1419], [0, 281], [0, 1177], [3, 645], [6, 230], [0, 799], [1, 30], [3, 0]]],
   [720, 720, 720, 700, 720, 720, 650, 620]],
  ['regression: scenario 4',
   [[[1, 1050, 700],
     [5, 1080, 700],
     [4, 1350, 680],
     [2, 720, 680],
     [0, 840, 720],
     [5, 1260, 600],
     [2, 750, 650],
     [0, 540, 600]],
    [[6, 269], [5, 893], [0, 381], [1, 1193], [4, 963], [5, 504], [3, 819], [1, 1050], [5, 1080]]],
   [600, 680, 600, 700, 650, 680, 650, 700, 700]],
  ['regression: week wrap and exact times',
   [[[0, 360, 700], [0, 1320, 620], [4, 360, 700], [4, 1380, 640]],
    [[0, 0], [0, 360], [1, 100], [4, 1379], [4, 1380], [6, 1439]]],
   [640, 700, 620, 700, 640, 640]],
  ['regression: unsorted entries',
   [[[2, 1200, 640], [2, 420, 700], [5, 480, 680]], [[2, 600], [3, 0], [1, 1439], [5, 480]]],
   [700, 640, 680, 680]],
  ['control: late evening event',
   [[[1, 1300, 600], [2, 200, 690]], [[1, 1350], [2, 100], [2, 300]]],
   [600, 600, 690]],
  ['control: tuesday first event',
   [[[1, 360, 700], [1, 1320, 620], [3, 600, 680]], [[1, 100], [2, 100], [0, 500]]],
   [680, 620, 680]],
  ['regression: scenario 1',
   [[[5, 1020, 600], [4, 900, 620], [5, 510, 680], [1, 1200, 680]],
    [[4, 860], [4, 862], [4, 1233], [4, 668], [4, 180], [0, 208], [2, 1192], [5, 1020], [4, 900]]],
   [680, 680, 620, 680, 680, 600, 680, 600, 620]],
  ['regression: scenario 2',
   [[[3, 330, 700],
     [1, 960, 700],
     [2, 540, 650],
     [3, 810, 600],
     [5, 1080, 700],
     [1, 300, 680],
     [6, 1020, 650]],
    [[6, 811], [3, 629], [0, 1103], [3, 1144], [4, 229], [3, 330], [1, 960]]],
   [700, 700, 650, 600, 600, 700, 700]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: week wrap and exact times[640, 700, 620, 700, 640, 640][640, 700, 620, 700, 640, 640]Passed
regression: unsorted entries[700, 640, 680, 680][700, 640, 680, 680]Passed
control: late evening event[600, 600, 690][600, 600, 690]Passed
control: tuesday first event[680, 620, 680][680, 620, 680]Passed
regression: scenario 1[720, 700, 700, 720, 720, 700][720, 700, 700, 720, 720, 700]Passed
control: scenario 2[650, 650, 650, 650, 650, 650, 650, 650, 650][650, 650, 650, 650, 650, 650, 650, 650, 650]Passed
regression: scenario 3[650, 650, 720, 720, 720, 720, 720, 600, 720][650, 650, 720, 720, 720, 720, 720, 600, 720]Passed
regression: scenario 4[600, 720, 650, 650, 650, 720, 650][600, 720, 650, 650, 650, 720, 650]Passed

SHA-256 / 7ccbd94da1064da385f0f15f8e17a1ee5e0b14f06ec9d4597a93bc3246b9adfd

Verification & scope

A deterministic bounded teaching model of one thermostat or HVAC controller decision evaluated per sample. Temperatures are integer tenths of a degree Fahrenheit unless stated otherwise. The contract is a stipulated toy convention, not a claim of conformance to any manufacturer, ASHRAE guideline or code. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:51:45.877838+00:00.

Case digest / 677e11d63dc9936962b9baaae278e5f2b4b017ae63dbde39e42b3cc11968fce5