FAILURE MAP
← Case archive

FA-92631 / HVAC thermostat control / Open access

Out-of-range remote sensor readings are averaged in · case 01

A shorted or open remote sensor drags the control temperature to an absurd value.

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

ROOT CAUSE

Validity only checks for a missing reading.

VERIFIED REPAIR

Discard readings outside 32.0-100.0 F.

Unsuccessful approach: Checking only the lower limit still accepts open-circuit high readings.

Case contract

Thermostat with remote room sensors; each sample is a list of [room, reading tenths F or None, occupied]. Readings outside 32.0-100.0 F or None are invalid. The control temperature is the mean of valid readings from occupied rooms, or of all valid readings if no occupied room has one, rounded half up to a tenth; if nothing is valid the previous control temperature is held (None initially). Return the control temperature per sample.

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(samples):
    last = None
    out = []
    for readings in samples:
        valid = [(t, occ) for room, t, occ in readings if t is not None]
        pool = [t for t, occ in valid if occ] or [t for t, occ in valid]
        if pool:
            last = (2 * sum(pool) + len(pool)) // (2 * len(pool))
        out.append(last)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 611, False], ['bed', 799, True]],
     [['living', 697, True]],
     [['living', 697, False], ['bed', 609, True]],
     [['living', 751, False], ['bed', 736, True], ['den', 616, True]],
     [['living', 1100, False], ['bed', 686, True]],
     [['living', 798, False], ['bed', 743, True], ['den', 646, False], ['office', 720, False]],
     [['living', 668, False], ['bed', None, True], ['den', None, True], ['office', 795, False]]]],
   [799, 697, 609, 676, 686, 743, 732]],
  ['regression: scenario 2',
   [[[['living', 602, False], ['bed', 665, False], ['den', 790, False], ['office', 677, False]],
     [['living', 638, False]],
     [['living', 602, False], ['bed', 750, True]],
     [['living', None, True], ['bed', 250, False], ['den', 250, True]],
     [['living', 744, True], ['bed', 711, True], ['den', 676, False], ['office', 640, True]],
     [['living', 771, False], ['bed', 646, True]],
     [['living', 608, False]],
     [['living', 663, True], ['bed', 793, True], ['den', 250, True], ['office', 743, False]]]],
   [684, 638, 750, 750, 698, 646, 608, 728]],
  ['regression: scenario 3',
   [[[['living', 677, True]],
     [['living', 624, True], ['bed', 620, True]],
     [['living', 605, True], ['bed', 250, False]],
     [['living', 764, False]],
     [['living', 612, False], ['bed', None, True], ['den', 664, True]],
     [['living', None, True], ['bed', 250, False], ['den', 250, True]],
     [['living', 745, True], ['bed', None, False]],
     [['living', 665, True]]]],
   [677, 622, 605, 764, 664, 664, 745, 665]],
  ['regression: scenario 4',
   [[[['living', 600, True]],
     [['living', 742, True], ['bed', 607, False], ['den', 638, True], ['office', 791, True]],
     [['living', 710, False], ['bed', 602, True], ['den', 716, False]],
     [['living', 607, False], ['bed', 735, True], ['den', 739, False], ['office', 723, True]],
     [['living', 621, True], ['bed', 625, False], ['den', 688, True], ['office', 627, False]],
     [['living', 677, False], ['bed', 775, True]],
     [['living', 1100, False], ['bed', None, False], ['den', 687, False]]]],
   [600, 724, 602, 729, 655, 775, 687]]],
 [['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['regression: scenario 4',
   [[[['living', 713, False]],
     [['living', 741, True], ['bed', 652, False], ['den', 796, False], ['office', 784, False]],
     [['living', 756, True], ['bed', 687, True], ['den', 250, False], ['office', 657, False]],
     [['living', 601, True], ['bed', 743, True], ['den', 250, True]],
     [['living', 728, False]],
     [['living', 605, False], ['bed', 766, True], ['den', 601, False]],
     [['living', 748, True]],
     [['living', 1100, True], ['bed', 622, False], ['den', 714, True], ['office', 644, True]],
     [['living', 773, True]]]],
   [713, 741, 722, 672, 728, 766, 748, 679, 773]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 631, False], ['bed', None, True]],
     [['living', 674, True], ['bed', 788, True]],
     [['living', 629, False]],
     [['living', 617, False], ['bed', 636, True], ['den', 622, True]],
     [['living', 602, True], ['bed', 659, True], ['den', 604, False]],
     [['living', 641, True], ['bed', 600, True]],
     [['living', 781, True]],
     [['living', 615, True], ['bed', 788, True], ['den', 658, True]]]],
   [631, 731, 629, 629, 631, 621, 781, 687]],
  ['control: scenario 2',
   [[[['living', 675, True], ['bed', 724, False], ['den', 793, True]],
     [['living', 711, False], ['bed', 720, False]],
     [['living', 722, False], ['bed', 1100, False], ['den', 606, False], ['office', 625, True]],
     [['living', 657, False], ['bed', 619, True], ['den', 800, True], ['office', 629, True]],
     [['living', 765, True], ['bed', 726, True]],
     [['living', 785, False], ['bed', 626, False]]]],
   [734, 716, 625, 683, 746, 706]],
  ['regression: scenario 3',
   [[[['living', 795, False]],
     [['living', 769, False], ['bed', 675, False]],
     [['living', 640, False]],
     [['living', None, False]],
     [['living', None, False], ['bed', 790, True], ['den', 684, False], ['office', 789, True]],
     [['living', 722, True], ['bed', 750, True], ['den', 250, True]],
     [['living', 663, True], ['bed', 670, True]],
     [['living', 628, False], ['bed', 687, False], ['den', 635, False]]]],
   [795, 722, 640, 640, 790, 736, 667, 650]]],
 [['regression: scenario 1',
   [[[['living', 627, False], ['bed', 693, True], ['den', 769, True], ['office', 704, True]],
     [['living', 738, True], ['bed', 638, True]],
     [['living', 760, True], ['bed', 696, True], ['den', 683, False]],
     [['living', 771, False], ['bed', 1100, False]],
     [['living', 686, True]],
     [['living', 734, True]],
     [['living', None, True], ['bed', 649, False], ['den', 767, False]],
     [['living', 722, True]],
     [['living', 686, True], ['bed', 715, False], ['den', 617, False], ['office', 250, False]],
     [['living', 790, True]]]],
   [722, 688, 728, 771, 686, 734, 708, 722, 686, 790]],
  ['regression: scenario 2',
   [[[['living', 663, False], ['bed', 781, True], ['den', 775, False], ['office', 722, True]],
     [['living', 655, False]],
     [['living', 777, False], ['bed', 790, True], ['den', 637, False], ['office', 682, False]],
     [['living', 250, False], ['bed', 701, True], ['den', 745, True], ['office', 626, False]],
     [['living', 619, False]],
     [['living', 619, True], ['bed', 710, True]],
     [['living', 732, False]],
     [['living', 772, False]],
     [['living', None, True], ['bed', 664, True], ['den', 728, True], ['office', 783, False]],
     [['living', 1100, True], ['bed', 734, True], ['den', 657, False], ['office', 601, False]]]],
   [752, 655, 790, 723, 619, 665, 732, 772, 696, 734]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['regression: scenario 3',
   [[[['living', 740, True], ['bed', None, False], ['den', 718, True], ['office', 628, True]],
     [['living', 687, True]],
     [['living', 766, True], ['bed', 604, False], ['den', 725, False], ['office', 735, False]],
     [['living', 788, False], ['bed', 698, False], ['den', 700, False], ['office', None, True]],
     [['living', None, False], ['bed', 607, True], ['den', 754, False]],
     [['living', 250, False], ['bed', 649, True], ['den', 666, False]],
     [['living', None, True], ['bed', 785, True]],
     [['living', 715, True], ['bed', 699, False], ['den', 1100, True]],
     [['living', 605, False], ['bed', 735, False]]]],
   [695, 687, 766, 729, 607, 649, 785, 715, 670]],
  ['regression: scenario 4',
   [[[['living', 647, True], ['bed', 693, False]],
     [['living', None, False], ['bed', 1100, False], ['den', None, True], ['office', None, False]],
     [['living', 791, False], ['bed', 250, False], ['den', 778, True]],
     [['living', 650, False], ['bed', None, True]],
     [['living', 1100, True], ['bed', 680, False], ['den', 250, False]],
     [['living', 700, True], ['bed', 1100, True], ['den', 712, False]],
     [['living', 662, True], ['bed', 670, True]]]],
   [647, 647, 778, 650, 680, 700, 666]]],
 [['regression: scenario 4',
   [[[['living', 614, False]],
     [['living', 616, True], ['bed', None, True], ['den', 783, True]],
     [['living', 250, True], ['bed', 250, True]],
     [['living', None, True]],
     [['living', 663, True]],
     [['living', 656, True], ['bed', 250, True], ['den', 679, True]],
     [['living', 799, True], ['bed', 707, True], ['den', 751, True]],
     [['living', None, True]]]],
   [614, 700, 700, 700, 663, 668, 752, 752]],
  ['regression: scenario 7',
   [[[['living', 776, True], ['bed', 1100, False], ['den', 734, False]],
     [['living', 250, True], ['bed', 734, False], ['den', 775, True], ['office', 1100, False]],
     [['living', 250, False], ['bed', 747, True], ['den', None, True]],
     [['living', 622, True], ['bed', 623, False], ['den', 793, True]],
     [['living', 728, True], ['bed', 708, True], ['den', None, False]],
     [['living', 644, False]],
     [['living', 765, True], ['bed', 650, True], ['den', 749, False], ['office', 1100, False]],
     [['living', 672, False], ['bed', 769, True], ['den', 1100, True]],
     [['living', 729, True], ['bed', None, False]],
     [['living', 794, False], ['bed', 670, True]]]],
   [776, 775, 747, 708, 718, 644, 708, 769, 729, 670]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 782, False], ['bed', 708, True], ['den', 678, True]],
     [['living', 772, False], ['bed', 795, True]],
     [['living', 744, True], ['bed', 616, True], ['den', 694, True]],
     [['living', 790, False], ['bed', 733, True]],
     [['living', 722, True], ['bed', 701, False]],
     [['living', 699, False], ['bed', 636, False]]]],
   [693, 795, 685, 733, 722, 668]],
  ['regression: scenario 2',
   [[[['living', 675, False], ['bed', 659, True], ['den', 738, False], ['office', 1100, False]],
     [['living', 250, True], ['bed', 649, True]],
     [['living', 604, True]],
     [['living', 629, True], ['bed', None, True], ['den', 610, True]],
     [['living', 633, False], ['bed', None, True], ['den', 778, True], ['office', 795, False]],
     [['living', None, False]]]],
   [659, 649, 604, 620, 778, 778]]],
 [['regression: scenario 3',
   [[[['living', None, True], ['bed', 631, True]],
     [['living', 654, False], ['bed', 779, False], ['den', 716, True]],
     [['living', 799, True]],
     [['living', 664, True]],
     [['living', 622, False]],
     [['living', 697, False], ['bed', 685, False]],
     [['living', 727, False], ['bed', 250, True], ['den', 737, False], ['office', 692, False]]]],
   [631, 716, 799, 664, 622, 691, 719]],
  ['regression: scenario 6',
   [[[['living', 696, False], ['bed', 633, True]],
     [['living', 662, False], ['bed', 1100, False]],
     [['living', 654, True]],
     [['living', 773, True], ['bed', 789, False], ['den', 791, True], ['office', 696, True]],
     [['living', 709, True], ['bed', 753, False]]]],
   [633, 662, 654, 753, 709]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['regression: scenario 1',
   [[[['living', 1100, True]],
     [['living', 634, False], ['bed', 740, False], ['den', None, True]],
     [['living', 1100, True]],
     [['living', 618, False], ['bed', 787, False], ['den', 754, False]],
     [['living', 673, False], ['bed', 795, True], ['den', 612, False], ['office', 721, True]]]],
   [None, 687, 687, 720, 758]],
  ['regression: scenario 2',
   [[[['living', 733, True], ['bed', 629, True], ['den', 631, True], ['office', 649, True]],
     [['living', 766, True]],
     [['living', 727, False], ['bed', 610, False]],
     [['living', None, True]],
     [['living', 627, False]],
     [['living', 689, True], ['bed', 635, True], ['den', 250, False]],
     [['living', 613, False], ['bed', 717, False]],
     [['living', 1100, True]]]],
   [661, 766, 669, 669, 627, 662, 665, 665]]]]
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: occupancy and faults[700, 686, 1200, 702][700, 686, 686, 702]Failed
regression: shorted sensor[353, 995][700, 690]Failed
control: first sample all invalid[None, 700, 700][None, 700, 700]Passed
control: single occupied room[700, 706][700, 706]Passed
control: scenario 1[799, 697, 609, 676, 686, 743, 732][799, 697, 609, 676, 686, 743, 732]Passed
regression: scenario 2[684, 638, 750, 250, 698, 646, 608, 569][684, 638, 750, 750, 698, 646, 608, 728]Failed
regression: scenario 3[677, 622, 605, 764, 664, 250, 745, 665][677, 622, 605, 764, 664, 664, 745, 665]Failed
regression: scenario 4[600, 724, 602, 729, 655, 775, 894][600, 724, 602, 729, 655, 775, 687]Failed

SHA-256 / b232091ab1c0c69181416233a9e378da52a958c7e90834939982b911f66543c9

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(samples):
    last = None
    out = []
    for readings in samples:
        valid = [(t, occ) for room, t, occ in readings if t is not None and t >= 320]
        pool = [t for t, occ in valid if occ] or [t for t, occ in valid]
        if pool:
            last = (2 * sum(pool) + len(pool)) // (2 * len(pool))
        out.append(last)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 611, False], ['bed', 799, True]],
     [['living', 697, True]],
     [['living', 697, False], ['bed', 609, True]],
     [['living', 751, False], ['bed', 736, True], ['den', 616, True]],
     [['living', 1100, False], ['bed', 686, True]],
     [['living', 798, False], ['bed', 743, True], ['den', 646, False], ['office', 720, False]],
     [['living', 668, False], ['bed', None, True], ['den', None, True], ['office', 795, False]]]],
   [799, 697, 609, 676, 686, 743, 732]],
  ['regression: scenario 2',
   [[[['living', 602, False], ['bed', 665, False], ['den', 790, False], ['office', 677, False]],
     [['living', 638, False]],
     [['living', 602, False], ['bed', 750, True]],
     [['living', None, True], ['bed', 250, False], ['den', 250, True]],
     [['living', 744, True], ['bed', 711, True], ['den', 676, False], ['office', 640, True]],
     [['living', 771, False], ['bed', 646, True]],
     [['living', 608, False]],
     [['living', 663, True], ['bed', 793, True], ['den', 250, True], ['office', 743, False]]]],
   [684, 638, 750, 750, 698, 646, 608, 728]],
  ['regression: scenario 3',
   [[[['living', 677, True]],
     [['living', 624, True], ['bed', 620, True]],
     [['living', 605, True], ['bed', 250, False]],
     [['living', 764, False]],
     [['living', 612, False], ['bed', None, True], ['den', 664, True]],
     [['living', None, True], ['bed', 250, False], ['den', 250, True]],
     [['living', 745, True], ['bed', None, False]],
     [['living', 665, True]]]],
   [677, 622, 605, 764, 664, 664, 745, 665]],
  ['regression: scenario 4',
   [[[['living', 600, True]],
     [['living', 742, True], ['bed', 607, False], ['den', 638, True], ['office', 791, True]],
     [['living', 710, False], ['bed', 602, True], ['den', 716, False]],
     [['living', 607, False], ['bed', 735, True], ['den', 739, False], ['office', 723, True]],
     [['living', 621, True], ['bed', 625, False], ['den', 688, True], ['office', 627, False]],
     [['living', 677, False], ['bed', 775, True]],
     [['living', 1100, False], ['bed', None, False], ['den', 687, False]]]],
   [600, 724, 602, 729, 655, 775, 687]]],
 [['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['regression: scenario 4',
   [[[['living', 713, False]],
     [['living', 741, True], ['bed', 652, False], ['den', 796, False], ['office', 784, False]],
     [['living', 756, True], ['bed', 687, True], ['den', 250, False], ['office', 657, False]],
     [['living', 601, True], ['bed', 743, True], ['den', 250, True]],
     [['living', 728, False]],
     [['living', 605, False], ['bed', 766, True], ['den', 601, False]],
     [['living', 748, True]],
     [['living', 1100, True], ['bed', 622, False], ['den', 714, True], ['office', 644, True]],
     [['living', 773, True]]]],
   [713, 741, 722, 672, 728, 766, 748, 679, 773]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 631, False], ['bed', None, True]],
     [['living', 674, True], ['bed', 788, True]],
     [['living', 629, False]],
     [['living', 617, False], ['bed', 636, True], ['den', 622, True]],
     [['living', 602, True], ['bed', 659, True], ['den', 604, False]],
     [['living', 641, True], ['bed', 600, True]],
     [['living', 781, True]],
     [['living', 615, True], ['bed', 788, True], ['den', 658, True]]]],
   [631, 731, 629, 629, 631, 621, 781, 687]],
  ['control: scenario 2',
   [[[['living', 675, True], ['bed', 724, False], ['den', 793, True]],
     [['living', 711, False], ['bed', 720, False]],
     [['living', 722, False], ['bed', 1100, False], ['den', 606, False], ['office', 625, True]],
     [['living', 657, False], ['bed', 619, True], ['den', 800, True], ['office', 629, True]],
     [['living', 765, True], ['bed', 726, True]],
     [['living', 785, False], ['bed', 626, False]]]],
   [734, 716, 625, 683, 746, 706]],
  ['regression: scenario 3',
   [[[['living', 795, False]],
     [['living', 769, False], ['bed', 675, False]],
     [['living', 640, False]],
     [['living', None, False]],
     [['living', None, False], ['bed', 790, True], ['den', 684, False], ['office', 789, True]],
     [['living', 722, True], ['bed', 750, True], ['den', 250, True]],
     [['living', 663, True], ['bed', 670, True]],
     [['living', 628, False], ['bed', 687, False], ['den', 635, False]]]],
   [795, 722, 640, 640, 790, 736, 667, 650]]],
 [['regression: scenario 1',
   [[[['living', 627, False], ['bed', 693, True], ['den', 769, True], ['office', 704, True]],
     [['living', 738, True], ['bed', 638, True]],
     [['living', 760, True], ['bed', 696, True], ['den', 683, False]],
     [['living', 771, False], ['bed', 1100, False]],
     [['living', 686, True]],
     [['living', 734, True]],
     [['living', None, True], ['bed', 649, False], ['den', 767, False]],
     [['living', 722, True]],
     [['living', 686, True], ['bed', 715, False], ['den', 617, False], ['office', 250, False]],
     [['living', 790, True]]]],
   [722, 688, 728, 771, 686, 734, 708, 722, 686, 790]],
  ['regression: scenario 2',
   [[[['living', 663, False], ['bed', 781, True], ['den', 775, False], ['office', 722, True]],
     [['living', 655, False]],
     [['living', 777, False], ['bed', 790, True], ['den', 637, False], ['office', 682, False]],
     [['living', 250, False], ['bed', 701, True], ['den', 745, True], ['office', 626, False]],
     [['living', 619, False]],
     [['living', 619, True], ['bed', 710, True]],
     [['living', 732, False]],
     [['living', 772, False]],
     [['living', None, True], ['bed', 664, True], ['den', 728, True], ['office', 783, False]],
     [['living', 1100, True], ['bed', 734, True], ['den', 657, False], ['office', 601, False]]]],
   [752, 655, 790, 723, 619, 665, 732, 772, 696, 734]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['regression: scenario 3',
   [[[['living', 740, True], ['bed', None, False], ['den', 718, True], ['office', 628, True]],
     [['living', 687, True]],
     [['living', 766, True], ['bed', 604, False], ['den', 725, False], ['office', 735, False]],
     [['living', 788, False], ['bed', 698, False], ['den', 700, False], ['office', None, True]],
     [['living', None, False], ['bed', 607, True], ['den', 754, False]],
     [['living', 250, False], ['bed', 649, True], ['den', 666, False]],
     [['living', None, True], ['bed', 785, True]],
     [['living', 715, True], ['bed', 699, False], ['den', 1100, True]],
     [['living', 605, False], ['bed', 735, False]]]],
   [695, 687, 766, 729, 607, 649, 785, 715, 670]],
  ['regression: scenario 4',
   [[[['living', 647, True], ['bed', 693, False]],
     [['living', None, False], ['bed', 1100, False], ['den', None, True], ['office', None, False]],
     [['living', 791, False], ['bed', 250, False], ['den', 778, True]],
     [['living', 650, False], ['bed', None, True]],
     [['living', 1100, True], ['bed', 680, False], ['den', 250, False]],
     [['living', 700, True], ['bed', 1100, True], ['den', 712, False]],
     [['living', 662, True], ['bed', 670, True]]]],
   [647, 647, 778, 650, 680, 700, 666]]],
 [['regression: scenario 4',
   [[[['living', 614, False]],
     [['living', 616, True], ['bed', None, True], ['den', 783, True]],
     [['living', 250, True], ['bed', 250, True]],
     [['living', None, True]],
     [['living', 663, True]],
     [['living', 656, True], ['bed', 250, True], ['den', 679, True]],
     [['living', 799, True], ['bed', 707, True], ['den', 751, True]],
     [['living', None, True]]]],
   [614, 700, 700, 700, 663, 668, 752, 752]],
  ['regression: scenario 7',
   [[[['living', 776, True], ['bed', 1100, False], ['den', 734, False]],
     [['living', 250, True], ['bed', 734, False], ['den', 775, True], ['office', 1100, False]],
     [['living', 250, False], ['bed', 747, True], ['den', None, True]],
     [['living', 622, True], ['bed', 623, False], ['den', 793, True]],
     [['living', 728, True], ['bed', 708, True], ['den', None, False]],
     [['living', 644, False]],
     [['living', 765, True], ['bed', 650, True], ['den', 749, False], ['office', 1100, False]],
     [['living', 672, False], ['bed', 769, True], ['den', 1100, True]],
     [['living', 729, True], ['bed', None, False]],
     [['living', 794, False], ['bed', 670, True]]]],
   [776, 775, 747, 708, 718, 644, 708, 769, 729, 670]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 782, False], ['bed', 708, True], ['den', 678, True]],
     [['living', 772, False], ['bed', 795, True]],
     [['living', 744, True], ['bed', 616, True], ['den', 694, True]],
     [['living', 790, False], ['bed', 733, True]],
     [['living', 722, True], ['bed', 701, False]],
     [['living', 699, False], ['bed', 636, False]]]],
   [693, 795, 685, 733, 722, 668]],
  ['regression: scenario 2',
   [[[['living', 675, False], ['bed', 659, True], ['den', 738, False], ['office', 1100, False]],
     [['living', 250, True], ['bed', 649, True]],
     [['living', 604, True]],
     [['living', 629, True], ['bed', None, True], ['den', 610, True]],
     [['living', 633, False], ['bed', None, True], ['den', 778, True], ['office', 795, False]],
     [['living', None, False]]]],
   [659, 649, 604, 620, 778, 778]]],
 [['regression: scenario 3',
   [[[['living', None, True], ['bed', 631, True]],
     [['living', 654, False], ['bed', 779, False], ['den', 716, True]],
     [['living', 799, True]],
     [['living', 664, True]],
     [['living', 622, False]],
     [['living', 697, False], ['bed', 685, False]],
     [['living', 727, False], ['bed', 250, True], ['den', 737, False], ['office', 692, False]]]],
   [631, 716, 799, 664, 622, 691, 719]],
  ['regression: scenario 6',
   [[[['living', 696, False], ['bed', 633, True]],
     [['living', 662, False], ['bed', 1100, False]],
     [['living', 654, True]],
     [['living', 773, True], ['bed', 789, False], ['den', 791, True], ['office', 696, True]],
     [['living', 709, True], ['bed', 753, False]]]],
   [633, 662, 654, 753, 709]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['regression: scenario 1',
   [[[['living', 1100, True]],
     [['living', 634, False], ['bed', 740, False], ['den', None, True]],
     [['living', 1100, True]],
     [['living', 618, False], ['bed', 787, False], ['den', 754, False]],
     [['living', 673, False], ['bed', 795, True], ['den', 612, False], ['office', 721, True]]]],
   [None, 687, 687, 720, 758]],
  ['regression: scenario 2',
   [[[['living', 733, True], ['bed', 629, True], ['den', 631, True], ['office', 649, True]],
     [['living', 766, True]],
     [['living', 727, False], ['bed', 610, False]],
     [['living', None, True]],
     [['living', 627, False]],
     [['living', 689, True], ['bed', 635, True], ['den', 250, False]],
     [['living', 613, False], ['bed', 717, False]],
     [['living', 1100, True]]]],
   [661, 766, 669, 669, 627, 662, 665, 665]]]]
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: occupancy and faults[700, 686, 1200, 702][700, 686, 686, 702]Failed
regression: shorted sensor[700, 995][700, 690]Failed
control: first sample all invalid[None, 700, 700][None, 700, 700]Passed
control: single occupied room[700, 706][700, 706]Passed
control: scenario 1[799, 697, 609, 676, 686, 743, 732][799, 697, 609, 676, 686, 743, 732]Passed
regression: scenario 2[684, 638, 750, 750, 698, 646, 608, 728][684, 638, 750, 750, 698, 646, 608, 728]Passed
regression: scenario 3[677, 622, 605, 764, 664, 664, 745, 665][677, 622, 605, 764, 664, 664, 745, 665]Passed
regression: scenario 4[600, 724, 602, 729, 655, 775, 894][600, 724, 602, 729, 655, 775, 687]Failed

SHA-256 / 2a3fc182c57b7efa2327573615ba261daf545e91c3881ba7f885b4f1cd74bfc1

3 / The verified repair

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

N = 1
observations = []
def solve(samples):
    last = None
    out = []
    for readings in samples:
        valid = [(t, occ) for room, t, occ in readings if t is not None and 320 <= t <= 1000]
        pool = [t for t, occ in valid if occ] or [t for t, occ in valid]
        if pool:
            last = (2 * sum(pool) + len(pool)) // (2 * len(pool))
        out.append(last)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 611, False], ['bed', 799, True]],
     [['living', 697, True]],
     [['living', 697, False], ['bed', 609, True]],
     [['living', 751, False], ['bed', 736, True], ['den', 616, True]],
     [['living', 1100, False], ['bed', 686, True]],
     [['living', 798, False], ['bed', 743, True], ['den', 646, False], ['office', 720, False]],
     [['living', 668, False], ['bed', None, True], ['den', None, True], ['office', 795, False]]]],
   [799, 697, 609, 676, 686, 743, 732]],
  ['regression: scenario 2',
   [[[['living', 602, False], ['bed', 665, False], ['den', 790, False], ['office', 677, False]],
     [['living', 638, False]],
     [['living', 602, False], ['bed', 750, True]],
     [['living', None, True], ['bed', 250, False], ['den', 250, True]],
     [['living', 744, True], ['bed', 711, True], ['den', 676, False], ['office', 640, True]],
     [['living', 771, False], ['bed', 646, True]],
     [['living', 608, False]],
     [['living', 663, True], ['bed', 793, True], ['den', 250, True], ['office', 743, False]]]],
   [684, 638, 750, 750, 698, 646, 608, 728]],
  ['regression: scenario 3',
   [[[['living', 677, True]],
     [['living', 624, True], ['bed', 620, True]],
     [['living', 605, True], ['bed', 250, False]],
     [['living', 764, False]],
     [['living', 612, False], ['bed', None, True], ['den', 664, True]],
     [['living', None, True], ['bed', 250, False], ['den', 250, True]],
     [['living', 745, True], ['bed', None, False]],
     [['living', 665, True]]]],
   [677, 622, 605, 764, 664, 664, 745, 665]],
  ['regression: scenario 4',
   [[[['living', 600, True]],
     [['living', 742, True], ['bed', 607, False], ['den', 638, True], ['office', 791, True]],
     [['living', 710, False], ['bed', 602, True], ['den', 716, False]],
     [['living', 607, False], ['bed', 735, True], ['den', 739, False], ['office', 723, True]],
     [['living', 621, True], ['bed', 625, False], ['den', 688, True], ['office', 627, False]],
     [['living', 677, False], ['bed', 775, True]],
     [['living', 1100, False], ['bed', None, False], ['den', 687, False]]]],
   [600, 724, 602, 729, 655, 775, 687]]],
 [['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['regression: scenario 4',
   [[[['living', 713, False]],
     [['living', 741, True], ['bed', 652, False], ['den', 796, False], ['office', 784, False]],
     [['living', 756, True], ['bed', 687, True], ['den', 250, False], ['office', 657, False]],
     [['living', 601, True], ['bed', 743, True], ['den', 250, True]],
     [['living', 728, False]],
     [['living', 605, False], ['bed', 766, True], ['den', 601, False]],
     [['living', 748, True]],
     [['living', 1100, True], ['bed', 622, False], ['den', 714, True], ['office', 644, True]],
     [['living', 773, True]]]],
   [713, 741, 722, 672, 728, 766, 748, 679, 773]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 631, False], ['bed', None, True]],
     [['living', 674, True], ['bed', 788, True]],
     [['living', 629, False]],
     [['living', 617, False], ['bed', 636, True], ['den', 622, True]],
     [['living', 602, True], ['bed', 659, True], ['den', 604, False]],
     [['living', 641, True], ['bed', 600, True]],
     [['living', 781, True]],
     [['living', 615, True], ['bed', 788, True], ['den', 658, True]]]],
   [631, 731, 629, 629, 631, 621, 781, 687]],
  ['control: scenario 2',
   [[[['living', 675, True], ['bed', 724, False], ['den', 793, True]],
     [['living', 711, False], ['bed', 720, False]],
     [['living', 722, False], ['bed', 1100, False], ['den', 606, False], ['office', 625, True]],
     [['living', 657, False], ['bed', 619, True], ['den', 800, True], ['office', 629, True]],
     [['living', 765, True], ['bed', 726, True]],
     [['living', 785, False], ['bed', 626, False]]]],
   [734, 716, 625, 683, 746, 706]],
  ['regression: scenario 3',
   [[[['living', 795, False]],
     [['living', 769, False], ['bed', 675, False]],
     [['living', 640, False]],
     [['living', None, False]],
     [['living', None, False], ['bed', 790, True], ['den', 684, False], ['office', 789, True]],
     [['living', 722, True], ['bed', 750, True], ['den', 250, True]],
     [['living', 663, True], ['bed', 670, True]],
     [['living', 628, False], ['bed', 687, False], ['den', 635, False]]]],
   [795, 722, 640, 640, 790, 736, 667, 650]]],
 [['regression: scenario 1',
   [[[['living', 627, False], ['bed', 693, True], ['den', 769, True], ['office', 704, True]],
     [['living', 738, True], ['bed', 638, True]],
     [['living', 760, True], ['bed', 696, True], ['den', 683, False]],
     [['living', 771, False], ['bed', 1100, False]],
     [['living', 686, True]],
     [['living', 734, True]],
     [['living', None, True], ['bed', 649, False], ['den', 767, False]],
     [['living', 722, True]],
     [['living', 686, True], ['bed', 715, False], ['den', 617, False], ['office', 250, False]],
     [['living', 790, True]]]],
   [722, 688, 728, 771, 686, 734, 708, 722, 686, 790]],
  ['regression: scenario 2',
   [[[['living', 663, False], ['bed', 781, True], ['den', 775, False], ['office', 722, True]],
     [['living', 655, False]],
     [['living', 777, False], ['bed', 790, True], ['den', 637, False], ['office', 682, False]],
     [['living', 250, False], ['bed', 701, True], ['den', 745, True], ['office', 626, False]],
     [['living', 619, False]],
     [['living', 619, True], ['bed', 710, True]],
     [['living', 732, False]],
     [['living', 772, False]],
     [['living', None, True], ['bed', 664, True], ['den', 728, True], ['office', 783, False]],
     [['living', 1100, True], ['bed', 734, True], ['den', 657, False], ['office', 601, False]]]],
   [752, 655, 790, 723, 619, 665, 732, 772, 696, 734]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['regression: scenario 3',
   [[[['living', 740, True], ['bed', None, False], ['den', 718, True], ['office', 628, True]],
     [['living', 687, True]],
     [['living', 766, True], ['bed', 604, False], ['den', 725, False], ['office', 735, False]],
     [['living', 788, False], ['bed', 698, False], ['den', 700, False], ['office', None, True]],
     [['living', None, False], ['bed', 607, True], ['den', 754, False]],
     [['living', 250, False], ['bed', 649, True], ['den', 666, False]],
     [['living', None, True], ['bed', 785, True]],
     [['living', 715, True], ['bed', 699, False], ['den', 1100, True]],
     [['living', 605, False], ['bed', 735, False]]]],
   [695, 687, 766, 729, 607, 649, 785, 715, 670]],
  ['regression: scenario 4',
   [[[['living', 647, True], ['bed', 693, False]],
     [['living', None, False], ['bed', 1100, False], ['den', None, True], ['office', None, False]],
     [['living', 791, False], ['bed', 250, False], ['den', 778, True]],
     [['living', 650, False], ['bed', None, True]],
     [['living', 1100, True], ['bed', 680, False], ['den', 250, False]],
     [['living', 700, True], ['bed', 1100, True], ['den', 712, False]],
     [['living', 662, True], ['bed', 670, True]]]],
   [647, 647, 778, 650, 680, 700, 666]]],
 [['regression: scenario 4',
   [[[['living', 614, False]],
     [['living', 616, True], ['bed', None, True], ['den', 783, True]],
     [['living', 250, True], ['bed', 250, True]],
     [['living', None, True]],
     [['living', 663, True]],
     [['living', 656, True], ['bed', 250, True], ['den', 679, True]],
     [['living', 799, True], ['bed', 707, True], ['den', 751, True]],
     [['living', None, True]]]],
   [614, 700, 700, 700, 663, 668, 752, 752]],
  ['regression: scenario 7',
   [[[['living', 776, True], ['bed', 1100, False], ['den', 734, False]],
     [['living', 250, True], ['bed', 734, False], ['den', 775, True], ['office', 1100, False]],
     [['living', 250, False], ['bed', 747, True], ['den', None, True]],
     [['living', 622, True], ['bed', 623, False], ['den', 793, True]],
     [['living', 728, True], ['bed', 708, True], ['den', None, False]],
     [['living', 644, False]],
     [['living', 765, True], ['bed', 650, True], ['den', 749, False], ['office', 1100, False]],
     [['living', 672, False], ['bed', 769, True], ['den', 1100, True]],
     [['living', 729, True], ['bed', None, False]],
     [['living', 794, False], ['bed', 670, True]]]],
   [776, 775, 747, 708, 718, 644, 708, 769, 729, 670]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['control: scenario 1',
   [[[['living', 782, False], ['bed', 708, True], ['den', 678, True]],
     [['living', 772, False], ['bed', 795, True]],
     [['living', 744, True], ['bed', 616, True], ['den', 694, True]],
     [['living', 790, False], ['bed', 733, True]],
     [['living', 722, True], ['bed', 701, False]],
     [['living', 699, False], ['bed', 636, False]]]],
   [693, 795, 685, 733, 722, 668]],
  ['regression: scenario 2',
   [[[['living', 675, False], ['bed', 659, True], ['den', 738, False], ['office', 1100, False]],
     [['living', 250, True], ['bed', 649, True]],
     [['living', 604, True]],
     [['living', 629, True], ['bed', None, True], ['den', 610, True]],
     [['living', 633, False], ['bed', None, True], ['den', 778, True], ['office', 795, False]],
     [['living', None, False]]]],
   [659, 649, 604, 620, 778, 778]]],
 [['regression: scenario 3',
   [[[['living', None, True], ['bed', 631, True]],
     [['living', 654, False], ['bed', 779, False], ['den', 716, True]],
     [['living', 799, True]],
     [['living', 664, True]],
     [['living', 622, False]],
     [['living', 697, False], ['bed', 685, False]],
     [['living', 727, False], ['bed', 250, True], ['den', 737, False], ['office', 692, False]]]],
   [631, 716, 799, 664, 622, 691, 719]],
  ['regression: scenario 6',
   [[[['living', 696, False], ['bed', 633, True]],
     [['living', 662, False], ['bed', 1100, False]],
     [['living', 654, True]],
     [['living', 773, True], ['bed', 789, False], ['den', 791, True], ['office', 696, True]],
     [['living', 709, True], ['bed', 753, False]]]],
   [633, 662, 654, 753, 709]],
  ['regression: occupancy and faults',
   [[[['liv', 700, True], ['bed', 680, False]],
     [['liv', None, True], ['bed', 681, False], ['den', 690, False]],
     [['liv', 1200, True]],
     [['liv', 701, True], ['bed', 702, True]]]],
   [700, 686, 686, 702]],
  ['regression: shorted sensor',
   [[[['a', 700, True], ['b', 5, True]], [['a', 1300, False], ['b', 690, False]]]],
   [700, 690]],
  ['control: first sample all invalid',
   [[[['a', None, True]], [['a', 700, True]], [['a', None, False]]]],
   [None, 700, 700]],
  ['control: single occupied room',
   [[[['a', 700, True], ['b', 650, False], ['c', 660, False]], [['a', 707, True], ['b', 704, True]]]],
   [700, 706]],
  ['regression: scenario 1',
   [[[['living', 1100, True]],
     [['living', 634, False], ['bed', 740, False], ['den', None, True]],
     [['living', 1100, True]],
     [['living', 618, False], ['bed', 787, False], ['den', 754, False]],
     [['living', 673, False], ['bed', 795, True], ['den', 612, False], ['office', 721, True]]]],
   [None, 687, 687, 720, 758]],
  ['regression: scenario 2',
   [[[['living', 733, True], ['bed', 629, True], ['den', 631, True], ['office', 649, True]],
     [['living', 766, True]],
     [['living', 727, False], ['bed', 610, False]],
     [['living', None, True]],
     [['living', 627, False]],
     [['living', 689, True], ['bed', 635, True], ['den', 250, False]],
     [['living', 613, False], ['bed', 717, False]],
     [['living', 1100, True]]]],
   [661, 766, 669, 669, 627, 662, 665, 665]]]]
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: occupancy and faults[700, 686, 686, 702][700, 686, 686, 702]Passed
regression: shorted sensor[700, 690][700, 690]Passed
control: first sample all invalid[None, 700, 700][None, 700, 700]Passed
control: single occupied room[700, 706][700, 706]Passed
control: scenario 1[799, 697, 609, 676, 686, 743, 732][799, 697, 609, 676, 686, 743, 732]Passed
regression: scenario 2[684, 638, 750, 750, 698, 646, 608, 728][684, 638, 750, 750, 698, 646, 608, 728]Passed
regression: scenario 3[677, 622, 605, 764, 664, 664, 745, 665][677, 622, 605, 764, 664, 664, 745, 665]Passed
regression: scenario 4[600, 724, 602, 729, 655, 775, 687][600, 724, 602, 729, 655, 775, 687]Passed

SHA-256 / 24e8dfb31ee9f79add1aee29ecbc8fa548591842406423591a53fe896a057f54

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:47.670699+00:00.

Case digest / ecf43ceaf078dbd593835016ff4c019b6c30b9efc91d2994ee227ac4434a9e24