broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(settings, samples):
    dehum = False
    cooling = False
    humid = False
    out = []
    for temp, rh, outdoor in samples:
        if dehum and rh <= settings['rh_sp'] + 5:
            dehum = False
        elif not dehum and rh > settings['rh_sp'] + 5:
            dehum = True
        eff = settings['cool_sp']
        if dehum:
            eff -= min(settings['max_overcool'], (rh - settings['rh_sp']) * 5)
        if cooling and temp <= eff:
            cooling = False
        elif not cooling and temp > eff + 10:
            cooling = True
        allowed = max(15, min(45, 40 + (outdoor - 20) // 10 * 5))
        target = min(settings['hum_sp'], allowed)
        if outdoor >= 50:
            humid = False
        elif humid and rh >= target:
            humid = False
        elif not humid and rh < target - 3:
            humid = True
        out.append([cooling, eff, humid])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['regression: scenario 52',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 50},
    [[742, 60, 46],
     [749, 57, 40],
     [738, 52, 29],
     [742, 55, 32],
     [736, 50, 28],
     [747, 52, 16],
     [748, 51, 17],
     [758, 56, 29],
     [763, 59, 33],
     [774, 56, 21],
     [776, 55, 14],
     [778, 55, 18],
     [771, 53, 27],
     [783, 51, 23]]],
   [[True, 720, False],
    [True, 720, False],
    [False, 740, False],
    [True, 725, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 725, False],
    [True, 725, False],
    [True, 735, False],
    [True, 745, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[738, 41, 24],
     [734, 38, 21],
     [725, 33, 9],
     [726, 34, -2],
     [733, 39, 7],
     [743, 36, 7],
     [740, 38, 7],
     [752, 32, 19],
     [742, 34, 11],
     [732, 32, 9]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[762, 20, -5],
     [767, 18, -6],
     [764, 13, -16],
     [765, 11, -12],
     [758, 10, -15],
     [757, 16, -3],
     [761, 16, 7],
     [758, 10, 13],
     [765, 10, 16],
     [763, 13, 12],
     [775, 16, 9],
     [765, 18, 4],
     [755, 20, 3],
     [754, 25, -3]]],
   [[True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, False]]]],
 [['regression: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[741, 58, -1],
     [736, 54, -9],
     [726, 56, 2],
     [715, 54, 0],
     [721, 55, 1],
     [732, 51, -1],
     [731, 51, -7],
     [727, 55, -12],
     [721, 57, -12]]],
   [[True, 720, False],
    [True, 730, False],
    [True, 720, False],
    [False, 730, False],
    [False, 725, False],
    [False, 745, False],
    [False, 745, False],
    [False, 725, False],
    [False, 720, False]]],
  ['regression: scenario 15',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 40},
    [[744, 62, 26],
     [743, 65, 35],
     [741, 60, 47],
     [753, 57, 53],
     [760, 51, 55],
     [760, 51, 47],
     [765, 50, 45],
     [768, 52, 53],
     [767, 56, 63],
     [769, 52, 66],
     [772, 51, 67],
     [771, 53, 63],
     [770, 47, 74],
     [762, 51, 66]]],
   [[True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 745, False],
    [True, 745, False],
    [True, 750, False],
    [True, 750, False],
    [True, 730, False],
    [True, 740, False],
    [True, 745, False],
    [True, 735, False],
    [True, 750, False],
    [True, 750, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['regression: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 40},
    [[749, 37, 58],
     [756, 33, 55],
     [768, 38, 65],
     [771, 41, 72],
     [780, 47, 71],
     [774, 50, 64],
     [770, 54, 73],
     [777, 59, 73],
     [786, 63, 85],
     [788, 59, 90],
     [790, 61, 90],
     [782, 58, 85],
     [790, 53, 80],
     [790, 48, 82]]],
   [[False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 750, False]]]],
 [['regression: scenario 6',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[761, 55, 45],
     [751, 61, 36],
     [763, 61, 26],
     [766, 62, 24],
     [770, 64, 24],
     [763, 60, 36],
     [775, 60, 31],
     [777, 55, 33],
     [774, 53, 39],
     [786, 52, 45],
     [780, 55, 49]]],
   [[True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 740, False],
    [True, 730, False]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 35},
    [[760, 30, 52],
     [750, 32, 60],
     [748, 28, 48],
     [744, 33, 44],
     [754, 37, 54],
     [748, 40, 55],
     [758, 39, 61],
     [760, 42, 61],
     [754, 36, 49],
     [742, 30, 44],
     [731, 32, 54],
     [739, 36, 48],
     [733, 36, 54]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[746, 32, -7],
     [745, 28, -12],
     [741, 24, -18],
     [736, 26, -12],
     [729, 31, 0],
     [720, 32, 7],
     [730, 30, 14],
     [728, 28, 19],
     [725, 23, 17],
     [729, 20, 18],
     [717, 24, 19],
     [715, 19, 10],
     [723, 14, 20],
     [722, 10, 23]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True]]]],
 [['regression: scenario 28',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[759, 56, 52],
     [769, 60, 63],
     [759, 57, 75],
     [770, 55, 70],
     [767, 56, 82],
     [768, 56, 70],
     [767, 56, 67],
     [757, 52, 61],
     [745, 49, 68],
     [735, 43, 67],
     [726, 44, 78],
     [721, 46, 78],
     [715, 52, 75]]],
   [[True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 725, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 740, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[741, 41, 9],
     [745, 42, 4],
     [749, 41, 7],
     [737, 37, 8],
     [740, 34, 14],
     [733, 38, 20],
     [730, 44, 9],
     [724, 38, 16],
     [725, 32, 6],
     [721, 27, -4]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[755, 29, 22],
     [752, 27, 11],
     [752, 25, 3],
     [763, 20, -7],
     [756, 25, -6],
     [766, 23, -4],
     [768, 25, 5],
     [774, 26, 7],
     [781, 22, -4]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [True, 750, True],
    [True, 750, False],
    [True, 750, False],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True]]]],
 [['regression: scenario 16',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[752, 42, -13],
     [740, 38, -2],
     [734, 33, -5],
     [734, 39, -6],
     [732, 38, 3],
     [733, 33, 3],
     [729, 35, 7],
     [729, 30, 12],
     [724, 36, 13],
     [718, 39, 8],
     [719, 45, 18],
     [729, 51, 20],
     [739, 57, 17],
     [739, 55, 16]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 730, False],
    [False, 730, False]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[755, 53, 26],
     [756, 54, 25],
     [766, 54, 30],
     [774, 48, 25],
     [783, 43, 35],
     [778, 37, 35],
     [777, 33, 39],
     [784, 35, 49],
     [779, 31, 39],
     [788, 27, 45],
     [778, 31, 42],
     [779, 31, 44],
     [789, 36, 51]]],
   [[False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[759, 30, 36],
     [770, 33, 36],
     [759, 34, 36],
     [752, 33, 36],
     [754, 27, 25],
     [764, 25, 15],
     [772, 25, 26],
     [784, 19, 22],
     [790, 21, 21]]],
   [[False, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True]]]]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(settings, samples):
    dehum = False
    cooling = False
    humid = False
    out = []
    for temp, rh, outdoor in samples:
        if dehum and rh < settings['rh_sp']:
            dehum = False
        elif not dehum and rh > settings['rh_sp'] + 5:
            dehum = True
        eff = settings['cool_sp']
        if dehum:
            eff -= min(settings['max_overcool'], (rh - settings['rh_sp']) * 5)
        if cooling and temp <= eff:
            cooling = False
        elif not cooling and temp > eff + 10:
            cooling = True
        allowed = max(15, min(45, 40 + (outdoor - 20) // 10 * 5))
        target = min(settings['hum_sp'], allowed)
        if outdoor >= 50:
            humid = False
        elif humid and rh >= target:
            humid = False
        elif not humid and rh < target - 3:
            humid = True
        out.append([cooling, eff, humid])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['regression: scenario 52',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 50},
    [[742, 60, 46],
     [749, 57, 40],
     [738, 52, 29],
     [742, 55, 32],
     [736, 50, 28],
     [747, 52, 16],
     [748, 51, 17],
     [758, 56, 29],
     [763, 59, 33],
     [774, 56, 21],
     [776, 55, 14],
     [778, 55, 18],
     [771, 53, 27],
     [783, 51, 23]]],
   [[True, 720, False],
    [True, 720, False],
    [False, 740, False],
    [True, 725, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 725, False],
    [True, 725, False],
    [True, 735, False],
    [True, 745, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[738, 41, 24],
     [734, 38, 21],
     [725, 33, 9],
     [726, 34, -2],
     [733, 39, 7],
     [743, 36, 7],
     [740, 38, 7],
     [752, 32, 19],
     [742, 34, 11],
     [732, 32, 9]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[762, 20, -5],
     [767, 18, -6],
     [764, 13, -16],
     [765, 11, -12],
     [758, 10, -15],
     [757, 16, -3],
     [761, 16, 7],
     [758, 10, 13],
     [765, 10, 16],
     [763, 13, 12],
     [775, 16, 9],
     [765, 18, 4],
     [755, 20, 3],
     [754, 25, -3]]],
   [[True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, False]]]],
 [['regression: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[741, 58, -1],
     [736, 54, -9],
     [726, 56, 2],
     [715, 54, 0],
     [721, 55, 1],
     [732, 51, -1],
     [731, 51, -7],
     [727, 55, -12],
     [721, 57, -12]]],
   [[True, 720, False],
    [True, 730, False],
    [True, 720, False],
    [False, 730, False],
    [False, 725, False],
    [False, 745, False],
    [False, 745, False],
    [False, 725, False],
    [False, 720, False]]],
  ['regression: scenario 15',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 40},
    [[744, 62, 26],
     [743, 65, 35],
     [741, 60, 47],
     [753, 57, 53],
     [760, 51, 55],
     [760, 51, 47],
     [765, 50, 45],
     [768, 52, 53],
     [767, 56, 63],
     [769, 52, 66],
     [772, 51, 67],
     [771, 53, 63],
     [770, 47, 74],
     [762, 51, 66]]],
   [[True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 745, False],
    [True, 745, False],
    [True, 750, False],
    [True, 750, False],
    [True, 730, False],
    [True, 740, False],
    [True, 745, False],
    [True, 735, False],
    [True, 750, False],
    [True, 750, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['regression: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 40},
    [[749, 37, 58],
     [756, 33, 55],
     [768, 38, 65],
     [771, 41, 72],
     [780, 47, 71],
     [774, 50, 64],
     [770, 54, 73],
     [777, 59, 73],
     [786, 63, 85],
     [788, 59, 90],
     [790, 61, 90],
     [782, 58, 85],
     [790, 53, 80],
     [790, 48, 82]]],
   [[False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 750, False]]]],
 [['regression: scenario 6',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[761, 55, 45],
     [751, 61, 36],
     [763, 61, 26],
     [766, 62, 24],
     [770, 64, 24],
     [763, 60, 36],
     [775, 60, 31],
     [777, 55, 33],
     [774, 53, 39],
     [786, 52, 45],
     [780, 55, 49]]],
   [[True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 740, False],
    [True, 730, False]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 35},
    [[760, 30, 52],
     [750, 32, 60],
     [748, 28, 48],
     [744, 33, 44],
     [754, 37, 54],
     [748, 40, 55],
     [758, 39, 61],
     [760, 42, 61],
     [754, 36, 49],
     [742, 30, 44],
     [731, 32, 54],
     [739, 36, 48],
     [733, 36, 54]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[746, 32, -7],
     [745, 28, -12],
     [741, 24, -18],
     [736, 26, -12],
     [729, 31, 0],
     [720, 32, 7],
     [730, 30, 14],
     [728, 28, 19],
     [725, 23, 17],
     [729, 20, 18],
     [717, 24, 19],
     [715, 19, 10],
     [723, 14, 20],
     [722, 10, 23]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, True]]]],
 [['regression: scenario 28',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[759, 56, 52],
     [769, 60, 63],
     [759, 57, 75],
     [770, 55, 70],
     [767, 56, 82],
     [768, 56, 70],
     [767, 56, 67],
     [757, 52, 61],
     [745, 49, 68],
     [735, 43, 67],
     [726, 44, 78],
     [721, 46, 78],
     [715, 52, 75]]],
   [[True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 725, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 740, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[741, 41, 9],
     [745, 42, 4],
     [749, 41, 7],
     [737, 37, 8],
     [740, 34, 14],
     [733, 38, 20],
     [730, 44, 9],
     [724, 38, 16],
     [725, 32, 6],
     [721, 27, -4]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[755, 29, 22],
     [752, 27, 11],
     [752, 25, 3],
     [763, 20, -7],
     [756, 25, -6],
     [766, 23, -4],
     [768, 25, 5],
     [774, 26, 7],
     [781, 22, -4]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [True, 750, True],
    [True, 750, False],
    [True, 750, False],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True]]]],
 [['regression: scenario 16',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[752, 42, -13],
     [740, 38, -2],
     [734, 33, -5],
     [734, 39, -6],
     [732, 38, 3],
     [733, 33, 3],
     [729, 35, 7],
     [729, 30, 12],
     [724, 36, 13],
     [718, 39, 8],
     [719, 45, 18],
     [729, 51, 20],
     [739, 57, 17],
     [739, 55, 16]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 730, False],
    [False, 730, False]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[755, 53, 26],
     [756, 54, 25],
     [766, 54, 30],
     [774, 48, 25],
     [783, 43, 35],
     [778, 37, 35],
     [777, 33, 39],
     [784, 35, 49],
     [779, 31, 39],
     [788, 27, 45],
     [778, 31, 42],
     [779, 31, 44],
     [789, 36, 51]]],
   [[False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[759, 30, 36],
     [770, 33, 36],
     [759, 34, 36],
     [752, 33, 36],
     [754, 27, 25],
     [764, 25, 15],
     [772, 25, 26],
     [784, 19, 22],
     [790, 21, 21]]],
   [[False, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True]]]]]
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)

prompt:
Dehumidification cycles on and off around rh_sp + 5 and never pulls humidity down to setpoint.

Thermostat humidity functions per sample; samples are [temp tenths F, indoor RH %, outdoor whole F]. Dehumidify-by-overcooling turns on when RH > rh_sp + 5 and off when RH <= rh_sp; while on, the effective cooling setpoint is lowered by min(max_overcool, (RH - rh_sp) * 5) tenths. Cooling starts above effective + 1.0 F and ends at <= effective. Humidifier: allowed RH = 40 + floor((outdoor - 20) / 10) * 5 clamped to 15..45; target = min(hum_sp, allowed); it is off when outdoor >= 50, otherwise starts below target - 3 and stops at >= target. Return [cooling, effective_sp, humidifier].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(settings, samples):
    dehum = False
    cooling = False
    humid = False
    out = []
    for temp, rh, outdoor in samples:
        if dehum and rh <= settings['rh_sp']:
            dehum = False
        elif not dehum and rh > settings['rh_sp'] + 5:
            dehum = True
        eff = settings['cool_sp']
        if dehum:
            eff -= (rh - settings['rh_sp']) * 5
        if cooling and temp <= eff:
            cooling = False
        elif not cooling and temp > eff + 10:
            cooling = True
        allowed = max(15, min(45, 40 + (outdoor - 20) // 10 * 5))
        target = min(settings['hum_sp'], allowed)
        if outdoor >= 50:
            humid = False
        elif humid and rh >= target:
            humid = False
        elif not humid and rh < target - 3:
            humid = True
        out.append([cooling, eff, humid])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[738, 41, 24],
     [734, 38, 21],
     [725, 33, 9],
     [726, 34, -2],
     [733, 39, 7],
     [743, 36, 7],
     [740, 38, 7],
     [752, 32, 19],
     [742, 34, 11],
     [732, 32, 9]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[762, 20, -5],
     [767, 18, -6],
     [764, 13, -16],
     [765, 11, -12],
     [758, 10, -15],
     [757, 16, -3],
     [761, 16, 7],
     [758, 10, 13],
     [765, 10, 16],
     [763, 13, 12],
     [775, 16, 9],
     [765, 18, 4],
     [755, 20, 3],
     [754, 25, -3]]],
   [[True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, False]]],
  ['control: scenario 3',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[741, 31, 49],
     [750, 36, 55],
     [739, 36, 59],
     [734, 34, 55],
     [728, 33, 56],
     [717, 35, 48],
     [715, 34, 60],
     [726, 38, 57],
     [726, 39, 57],
     [719, 34, 54],
     [726, 39, 57],
     [729, 41, 61],
     [732, 39, 66],
     [743, 40, 75]]],
   [[False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]]],
 [['regression: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[741, 58, -1],
     [736, 54, -9],
     [726, 56, 2],
     [715, 54, 0],
     [721, 55, 1],
     [732, 51, -1],
     [731, 51, -7],
     [727, 55, -12],
     [721, 57, -12]]],
   [[True, 720, False],
    [True, 730, False],
    [True, 720, False],
    [False, 730, False],
    [False, 725, False],
    [False, 745, False],
    [False, 745, False],
    [False, 725, False],
    [False, 720, False]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['regression: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 40},
    [[749, 37, 58],
     [756, 33, 55],
     [768, 38, 65],
     [771, 41, 72],
     [780, 47, 71],
     [774, 50, 64],
     [770, 54, 73],
     [777, 59, 73],
     [786, 63, 85],
     [788, 59, 90],
     [790, 61, 90],
     [782, 58, 85],
     [790, 53, 80],
     [790, 48, 82]]],
   [[False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 750, False]]],
  ['regression: scenario 3',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[757, 59, 32],
     [758, 65, 22],
     [769, 68, 15],
     [759, 74, 20],
     [747, 72, 31],
     [739, 66, 32],
     [736, 70, 38],
     [744, 65, 29],
     [745, 62, 40],
     [753, 57, 46],
     [759, 61, 35],
     [749, 57, 29]]],
   [[True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False]]]],
 [['regression: scenario 6',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[761, 55, 45],
     [751, 61, 36],
     [763, 61, 26],
     [766, 62, 24],
     [770, 64, 24],
     [763, 60, 36],
     [775, 60, 31],
     [777, 55, 33],
     [774, 53, 39],
     [786, 52, 45],
     [780, 55, 49]]],
   [[True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 740, False],
    [True, 730, False]]],
  ['regression: scenario 3',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[757, 58, 62],
     [767, 52, 71],
     [773, 56, 59],
     [776, 56, 64],
     [765, 59, 59],
     [759, 53, 53],
     [771, 51, 47],
     [775, 55, 38],
     [773, 53, 28],
     [777, 59, 17],
     [785, 57, 9],
     [777, 61, 4]]],
   [[True, 730, False],
    [True, 740, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 745, False],
    [True, 730, False],
    [True, 735, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False]]],
  ['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 35},
    [[760, 30, 52],
     [750, 32, 60],
     [748, 28, 48],
     [744, 33, 44],
     [754, 37, 54],
     [748, 40, 55],
     [758, 39, 61],
     [760, 42, 61],
     [754, 36, 49],
     [742, 30, 44],
     [731, 32, 54],
     [739, 36, 48],
     [733, 36, 54]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]]],
 [['regression: scenario 10',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[738, 51, -21],
     [750, 57, -9],
     [750, 63, -19],
     [751, 61, -8],
     [743, 64, -17],
     [750, 66, -28],
     [747, 65, -30],
     [741, 71, -23],
     [739, 71, -30],
     [738, 69, -24],
     [749, 70, -17],
     [758, 74, -27],
     [765, 75, -28],
     [769, 69, -30]]],
   [[False, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False]]],
  ['regression: scenario 8',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[741, 63, 56],
     [745, 61, 50],
     [746, 59, 52],
     [739, 63, 40],
     [741, 57, 41],
     [734, 61, 32],
     [732, 62, 40],
     [743, 68, 30],
     [755, 73, 18],
     [744, 75, 9],
     [746, 75, 7],
     [757, 75, 14]]],
   [[True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False]]],
  ['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[741, 41, 9],
     [745, 42, 4],
     [749, 41, 7],
     [737, 37, 8],
     [740, 34, 14],
     [733, 38, 20],
     [730, 44, 9],
     [724, 38, 16],
     [725, 32, 6],
     [721, 27, -4]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]]],
 [['regression: scenario 9',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[755, 44, 17],
     [747, 40, 16],
     [745, 41, 7],
     [754, 44, 8],
     [752, 44, -2],
     [764, 43, 3],
     [762, 49, 12],
     [769, 50, 8],
     [777, 54, 1],
     [782, 55, -5],
     [790, 60, -11],
     [790, 58, -4],
     [786, 63, -14],
     [787, 67, -13]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False]]],
  ['regression: scenario 7',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 40},
    [[744, 61, 53],
     [737, 62, 52],
     [732, 64, 57],
     [721, 68, 54],
     [715, 62, 53],
     [723, 59, 61],
     [715, 55, 68],
     [722, 56, 61],
     [734, 53, 64],
     [722, 57, 58],
     [723, 63, 49],
     [724, 69, 52]]],
   [[True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [False, 730, False],
    [False, 730, False],
    [False, 730, False],
    [False, 730, False],
    [False, 730, False],
    [False, 735, False],
    [False, 730, False],
    [False, 730, False],
    [False, 730, False]]],
  ['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[755, 53, 26],
     [756, 54, 25],
     [766, 54, 30],
     [774, 48, 25],
     [783, 43, 35],
     [778, 37, 35],
     [777, 33, 39],
     [784, 35, 49],
     [779, 31, 39],
     [788, 27, 45],
     [778, 31, 42],
     [779, 31, 44],
     [789, 36, 51]]],
   [[False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, False]]]]]
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)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(settings, samples):
    dehum = False
    cooling = False
    humid = False
    out = []
    for temp, rh, outdoor in samples:
        if dehum and rh <= settings['rh_sp']:
            dehum = False
        elif not dehum and rh > settings['rh_sp'] + 5:
            dehum = True
        eff = settings['cool_sp']
        if dehum:
            eff -= min(settings['max_overcool'], (rh - settings['rh_sp'] - 5) * 5)
        if cooling and temp <= eff:
            cooling = False
        elif not cooling and temp > eff + 10:
            cooling = True
        allowed = max(15, min(45, 40 + (outdoor - 20) // 10 * 5))
        target = min(settings['hum_sp'], allowed)
        if outdoor >= 50:
            humid = False
        elif humid and rh >= target:
            humid = False
        elif not humid and rh < target - 3:
            humid = True
        out.append([cooling, eff, humid])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[738, 41, 24],
     [734, 38, 21],
     [725, 33, 9],
     [726, 34, -2],
     [733, 39, 7],
     [743, 36, 7],
     [740, 38, 7],
     [752, 32, 19],
     [742, 34, 11],
     [732, 32, 9]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[762, 20, -5],
     [767, 18, -6],
     [764, 13, -16],
     [765, 11, -12],
     [758, 10, -15],
     [757, 16, -3],
     [761, 16, 7],
     [758, 10, 13],
     [765, 10, 16],
     [763, 13, 12],
     [775, 16, 9],
     [765, 18, 4],
     [755, 20, 3],
     [754, 25, -3]]],
   [[True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, False]]],
  ['control: scenario 3',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[741, 31, 49],
     [750, 36, 55],
     [739, 36, 59],
     [734, 34, 55],
     [728, 33, 56],
     [717, 35, 48],
     [715, 34, 60],
     [726, 38, 57],
     [726, 39, 57],
     [719, 34, 54],
     [726, 39, 57],
     [729, 41, 61],
     [732, 39, 66],
     [743, 40, 75]]],
   [[False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]]],
 [['regression: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[741, 58, -1],
     [736, 54, -9],
     [726, 56, 2],
     [715, 54, 0],
     [721, 55, 1],
     [732, 51, -1],
     [731, 51, -7],
     [727, 55, -12],
     [721, 57, -12]]],
   [[True, 720, False],
    [True, 730, False],
    [True, 720, False],
    [False, 730, False],
    [False, 725, False],
    [False, 745, False],
    [False, 745, False],
    [False, 725, False],
    [False, 720, False]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['regression: scenario 2',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 40},
    [[749, 37, 58],
     [756, 33, 55],
     [768, 38, 65],
     [771, 41, 72],
     [780, 47, 71],
     [774, 50, 64],
     [770, 54, 73],
     [777, 59, 73],
     [786, 63, 85],
     [788, 59, 90],
     [790, 61, 90],
     [782, 58, 85],
     [790, 53, 80],
     [790, 48, 82]]],
   [[False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 750, False]]],
  ['regression: scenario 3',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[757, 59, 32],
     [758, 65, 22],
     [769, 68, 15],
     [759, 74, 20],
     [747, 72, 31],
     [739, 66, 32],
     [736, 70, 38],
     [744, 65, 29],
     [745, 62, 40],
     [753, 57, 46],
     [759, 61, 35],
     [749, 57, 29]]],
   [[True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False]]]],
 [['regression: scenario 6',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[761, 55, 45],
     [751, 61, 36],
     [763, 61, 26],
     [766, 62, 24],
     [770, 64, 24],
     [763, 60, 36],
     [775, 60, 31],
     [777, 55, 33],
     [774, 53, 39],
     [786, 52, 45],
     [780, 55, 49]]],
   [[True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 740, False],
    [True, 730, False]]],
  ['regression: scenario 3',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[757, 58, 62],
     [767, 52, 71],
     [773, 56, 59],
     [776, 56, 64],
     [765, 59, 59],
     [759, 53, 53],
     [771, 51, 47],
     [775, 55, 38],
     [773, 53, 28],
     [777, 59, 17],
     [785, 57, 9],
     [777, 61, 4]]],
   [[True, 730, False],
    [True, 740, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 735, False],
    [True, 745, False],
    [True, 730, False],
    [True, 735, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False]]],
  ['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 35},
    [[760, 30, 52],
     [750, 32, 60],
     [748, 28, 48],
     [744, 33, 44],
     [754, 37, 54],
     [748, 40, 55],
     [758, 39, 61],
     [760, 42, 61],
     [754, 36, 49],
     [742, 30, 44],
     [731, 32, 54],
     [739, 36, 48],
     [733, 36, 54]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]]],
 [['regression: scenario 10',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[738, 51, -21],
     [750, 57, -9],
     [750, 63, -19],
     [751, 61, -8],
     [743, 64, -17],
     [750, 66, -28],
     [747, 65, -30],
     [741, 71, -23],
     [739, 71, -30],
     [738, 69, -24],
     [749, 70, -17],
     [758, 74, -27],
     [765, 75, -28],
     [769, 69, -30]]],
   [[False, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False]]],
  ['regression: scenario 8',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 45},
    [[741, 63, 56],
     [745, 61, 50],
     [746, 59, 52],
     [739, 63, 40],
     [741, 57, 41],
     [734, 61, 32],
     [732, 62, 40],
     [743, 68, 30],
     [755, 73, 18],
     [744, 75, 9],
     [746, 75, 7],
     [757, 75, 14]]],
   [[True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False],
    [True, 720, False]]],
  ['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[741, 41, 9],
     [745, 42, 4],
     [749, 41, 7],
     [737, 37, 8],
     [740, 34, 14],
     [733, 38, 20],
     [730, 44, 9],
     [724, 38, 16],
     [725, 32, 6],
     [721, 27, -4]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]]],
 [['regression: scenario 9',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[755, 44, 17],
     [747, 40, 16],
     [745, 41, 7],
     [754, 44, 8],
     [752, 44, -2],
     [764, 43, 3],
     [762, 49, 12],
     [769, 50, 8],
     [777, 54, 1],
     [782, 55, -5],
     [790, 60, -11],
     [790, 58, -4],
     [786, 63, -14],
     [787, 67, -13]]],
   [[False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [True, 730, False]]],
  ['regression: scenario 7',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 40},
    [[744, 61, 53],
     [737, 62, 52],
     [732, 64, 57],
     [721, 68, 54],
     [715, 62, 53],
     [723, 59, 61],
     [715, 55, 68],
     [722, 56, 61],
     [734, 53, 64],
     [722, 57, 58],
     [723, 63, 49],
     [724, 69, 52]]],
   [[True, 730, False],
    [True, 730, False],
    [True, 730, False],
    [False, 730, False],
    [False, 730, False],
    [False, 730, False],
    [False, 730, False],
    [False, 730, False],
    [False, 735, False],
    [False, 730, False],
    [False, 730, False],
    [False, 730, False]]],
  ['regression: summer then winter',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[765, 52, 80],
     [762, 58, 80],
     [745, 58, 80],
     [738, 50, 80],
     [700, 25, 10],
     [700, 29, 10],
     [700, 36, 10],
     [700, 10, -15]]],
   [[True, 750, False],
    [True, 720, False],
    [True, 720, False],
    [False, 750, False],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True]]],
  ['regression: dehumidify band',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 30, 'hum_sp': 40},
    [[760, 56, 80],
     [752, 53, 80],
     [745, 52, 80],
     [741, 51, 80],
     [741, 50, 80],
     [752, 52, 80],
     [749, 52, 80]]],
   [[True, 720, False],
    [True, 735, False],
    [True, 740, False],
    [False, 745, False],
    [False, 750, False],
    [False, 750, False],
    [False, 750, False]]],
  ['control: frost limit steps',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 30, 25], [700, 33, 29], [700, 36, 30], [700, 36, -5], [700, 10, -40], [700, 30, 55]]],
   [[False, 750, True],
    [False, 750, True],
    [False, 750, True],
    [False, 750, False],
    [False, 750, True],
    [False, 750, False]]],
  ['control: mild dry day',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 50},
    [[700, 40, 45], [700, 43, 45], [700, 46, 45], [700, 48, 45]]],
   [[False, 750, True], [False, 750, True], [False, 750, False], [False, 750, False]]],
  ['control: cold snap',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 45},
    [[700, 12, -60], [700, 14, -60], [700, 16, -60], [700, 20, 50], [700, 20, 49]]],
   [[False, 750, False], [False, 750, False], [False, 750, False], [False, 750, False], [False, 750, True]]],
  ['control: scenario 1',
   [{'cool_sp': 750, 'rh_sp': 50, 'max_overcool': 20, 'hum_sp': 35},
    [[755, 53, 26],
     [756, 54, 25],
     [766, 54, 30],
     [774, 48, 25],
     [783, 43, 35],
     [778, 37, 35],
     [777, 33, 39],
     [784, 35, 49],
     [779, 31, 39],
     [788, 27, 45],
     [778, 31, 42],
     [779, 31, 44],
     [789, 36, 51]]],
   [[False, 750, False],
    [False, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, False],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, True],
    [True, 750, False]]]]]
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)

prompt:
Very humid days drive the cooling setpoint several degrees below what the user set.

Thermostat humidity functions per sample; samples are [temp tenths F, indoor RH %, outdoor whole F]. Dehumidify-by-overcooling turns on when RH > rh_sp + 5 and off when RH <= rh_sp; while on, the effective cooling setpoint is lowered by min(max_overcool, (RH - rh_sp) * 5) tenths. Cooling starts above effective + 1.0 F and ends at <= effective. Humidifier: allowed RH = 40 + floor((outdoor - 20) / 10) * 5 clamped to 15..45; target = min(hum_sp, allowed); it is off when outdoor >= 50, otherwise starts below target - 3 and stops at >= target. Return [cooling, effective_sp, humidifier].

split: open-access