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

N = 1
observations = []
def solve(max_run, samples):
    mode = None
    since = 0
    out = []
    for minute, calls in enumerate(samples):
        heat = sorted(z for z, c in calls.items() if c == 'heat')
        cool = sorted(z for z, c in calls.items() if c == 'cool')
        want = {'heat': heat, 'cool': cool}
        if mode is not None:
            other = 'cool' if mode == 'heat' else 'heat'
            if not want[mode]:
                mode = None
            elif want[other] and minute - since >= max_run:
                mode = other
                since = minute
        if mode is None and (heat or cool):
            mode = 'heat' if len(heat) >= len(cool) else 'cool'
            since = minute
        out.append([mode, sorted(heat + cool) if mode else []])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z3': None, 'z4': None},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None, 'z4': 'cool'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'}]],
   [['cool', ['z1']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z4']],
    ['heat', ['z3', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'heat'},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1', 'z3']]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z3': 'heat'}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z1']]]]],
 [['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool'}]],
   [['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: scenario 2',
   [3,
    [{'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'cool'},
     {'z3': 'cool'},
     {'z2': None, 'z3': 'cool', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']]]],
  ['regression: scenario 3',
   [3,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']]]]],
 [['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': None}]],
   [['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z2']]]],
  ['regression: scenario 2',
   [2,
    [{'z1': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z3': None}]],
   [['cool', ['z3', 'z4']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    [None, []]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3', 'z4']],
    ['heat', ['z2', 'z4']]]]],
 [['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'heat', 'z4': 'cool'}]],
   [['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z3']],
    ['cool', ['z1']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z3']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 2',
   [2,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': None, 'z3': 'cool'}]],
   [['heat', ['z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: scenario 3',
   [5,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z1', 'z4']],
    ['cool', ['z2', 'z3']]]]],
 [['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat'},
     {'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': None, 'z4': 'heat'},
     {'z2': 'heat', 'z3': None, 'z4': 'heat'}]],
   [['heat', ['z1', 'z2', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z3']],
    ['heat', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'}]],
   [['cool', ['z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z1', 'z2', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z3']]]]]]
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(max_run, samples):
    mode = None
    since = 0
    out = []
    for minute, calls in enumerate(samples):
        heat = sorted(z for z, c in calls.items() if c == 'heat')
        cool = sorted(z for z, c in calls.items() if c == 'cool')
        want = {'heat': heat, 'cool': cool}
        if mode is not None:
            other = 'cool' if mode == 'heat' else 'heat'
            if not want[mode]:
                mode = None
            elif want[other] and minute - since >= max_run:
                mode = other
                since = minute
        if mode is None and (heat or cool):
            mode = 'heat' if len(heat) >= len(cool) else 'cool'
            since = minute
        out.append([mode, sorted(calls) if mode else []])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z3': None, 'z4': None},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': None, 'z4': 'cool'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'}]],
   [['cool', ['z1']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z4']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z4']],
    ['heat', ['z3', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'heat'},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': None, 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1']],
    ['heat', ['z1', 'z3']]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z3': 'heat'}]],
   [['cool', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z1']]]]],
 [['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': None, 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool'}]],
   [['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: scenario 2',
   [3,
    [{'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'cool'},
     {'z3': 'cool'},
     {'z2': None, 'z3': 'cool', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z3', 'z4']],
    ['heat', ['z3', 'z4']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z1', 'z2']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']]]],
  ['regression: scenario 3',
   [3,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']]]]],
 [['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None},
     {'z1': 'heat', 'z2': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': 'cool'},
     {'z1': 'heat', 'z2': 'heat', 'z3': None, 'z4': None}]],
   [['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z1', 'z2', 'z4']],
    ['heat', ['z1', 'z2']],
    ['heat', ['z1', 'z2']],
    ['cool', ['z4']],
    ['heat', ['z1', 'z2']]]],
  ['regression: scenario 2',
   [2,
    [{'z1': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z1': None, 'z2': 'cool', 'z3': None, 'z4': 'heat'},
     {'z2': 'cool', 'z4': 'heat'},
     {'z3': None}]],
   [['cool', ['z3', 'z4']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z4']],
    [None, []]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'}]],
   [['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3', 'z4']],
    ['heat', ['z2', 'z4']]]]],
 [['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['regression: scenario 1',
   [5,
    [{'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': None, 'z3': 'cool', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z4': 'heat'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'heat', 'z3': 'heat', 'z4': 'cool'}]],
   [['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['cool', ['z3']],
    ['cool', ['z1']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z3']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 2',
   [2,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': None},
     {'z2': None, 'z3': 'cool'}]],
   [['heat', ['z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z2', 'z3']],
    ['cool', ['z3']]]],
  ['regression: scenario 3',
   [5,
    [{'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'heat'}]],
   [['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z2', 'z3']],
    ['cool', ['z1', 'z3']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z4']],
    ['heat', ['z1', 'z4']],
    ['cool', ['z2', 'z3']]]]],
 [['regression: scenario 1',
   [3,
    [{'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'heat', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z1': 'heat', 'z2': 'heat', 'z3': 'cool', 'z4': 'heat'},
     {'z2': 'heat'},
     {'z2': 'heat', 'z4': 'heat'},
     {'z1': None, 'z2': 'heat', 'z3': None, 'z4': 'heat'},
     {'z2': 'heat', 'z3': None, 'z4': 'heat'}]],
   [['heat', ['z1', 'z2', 'z3', 'z4']],
    ['heat', ['z1', 'z2', 'z3']],
    ['heat', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z3']],
    ['cool', ['z3']],
    ['heat', ['z2']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']],
    ['heat', ['z2', 'z4']]]],
  ['regression: scenario 2',
   [5,
    [{'z1': 'cool', 'z2': None, 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': None, 'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat'},
     {'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat'},
     {'z1': 'heat', 'z2': 'cool', 'z3': 'heat', 'z4': None},
     {'z2': 'cool', 'z3': 'heat', 'z4': None}]],
   [['cool', ['z1', 'z4']],
    ['cool', ['z1', 'z4']],
    ['cool', ['z1']],
    ['cool', ['z2']],
    ['cool', ['z2']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['heat', ['z1', 'z3']],
    ['heat', ['z1', 'z3']],
    ['cool', ['z2']]]],
  ['regression: majority then forced switch',
   [3,
    [{'a': 'heat', 'b': 'cool', 'c': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat'},
     {}]],
   [['cool', ['b', 'c']], ['cool', ['b']], ['cool', ['b']], ['heat', ['a']], ['heat', ['a']], [None, []]]],
  ['regression: tie goes to heat',
   [2, [{'a': 'heat', 'b': 'cool'}, {'a': 'heat', 'b': 'cool'}, {'b': 'cool'}]],
   [['heat', ['a']], ['heat', ['a']], ['cool', ['b']]]],
  ['regression: ping pong guard',
   [2,
    [{'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'},
     {'a': 'heat', 'b': 'cool'}]],
   [['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']],
    ['cool', ['b']],
    ['heat', ['a']],
    ['heat', ['a']],
    ['cool', ['b']]]],
  ['regression: satisfied then opposite',
   [5, [{'a': 'cool'}, {'a': 'cool', 'b': 'heat'}, {'b': 'heat'}, {'b': 'heat'}]],
   [['cool', ['a']], ['cool', ['a']], ['heat', ['b']], ['heat', ['b']]]],
  ['control: first minute call',
   [3, [{'a': 'cool'}, {'a': 'cool'}, {}]],
   [['cool', ['a']], ['cool', ['a']], [None, []]]],
  ['regression: scenario 3',
   [2,
    [{'z1': 'heat', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z2': 'cool', 'z3': 'cool', 'z4': 'cool'},
     {'z1': None, 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z2': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'},
     {'z1': 'cool', 'z3': 'heat', 'z4': 'cool'}]],
   [['cool', ['z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z1', 'z2', 'z3', 'z4']],
    ['cool', ['z2', 'z3', 'z4']],
    ['heat', ['z3']],
    ['heat', ['z3']],
    ['cool', ['z1', 'z2', 'z4']],
    ['cool', ['z1', 'z4']],
    ['heat', ['z3']]]]]]
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:
A zone calling for heat receives cooled air while the system is cooling.

Zoned single-unit system arbitration per minute; each sample maps zone -> heat, cool or None. When idle the system picks the mode with more calling zones (ties go to heat). A mode ends when no zone calls for it, and a new mode may be chosen in the same minute. If zones call for the opposite mode, the system switches once the current mode has run max_run minutes, restarting the run timer. Dampers open only for zones calling the active mode. Return [mode, sorted open zones] per minute.

split: open-access


meaning: Fixture-count band, not measured model difficulty

deps: stdlib

prompt:
Energy is planned into the slot in which the driver has already unplugged.

prices[i] is the tariff in cents/kWh of 15-minute slot i. The car is present for slots arrive..depart-1 (depart exclusive) clipped to the tariff horizon; arrive may be negative. Each slot delivers at most max_w//4 Wh. Fill the cheapest slots first (equal price: earlier slot first), the last slot partially. Return [[slot, wh] sorted by slot, cost in millicents (sum wh*price), unmet wh]. need_wh<=0 or max_w<=0 returns [[], 0, max(need_wh,0)].

split: open-access


prompt:
With a flat tariff the plan charges at the end of the stay instead of as early as possible.

prices[i] is the tariff in cents/kWh of 15-minute slot i. The car is present for slots arrive..depart-1 (depart exclusive) clipped to the tariff horizon; arrive may be negative. Each slot delivers at most max_w//4 Wh. Fill the cheapest slots first (equal price: earlier slot first), the last slot partially. Return [[slot, wh] sorted by slot, cost in millicents (sum wh*price), unmet wh]. need_wh<=0 or max_w<=0 returns [[], 0, max(need_wh,0)].

split: open-access


prompt:
A 7.4 kW charger is scheduled to deliver 7.4 kWh inside a quarter hour.

prices[i] is the tariff in cents/kWh of 15-minute slot i. The car is present for slots arrive..depart-1 (depart exclusive) clipped to the tariff horizon; arrive may be negative. Each slot delivers at most max_w//4 Wh. Fill the cheapest slots first (equal price: earlier slot first), the last slot partially. Return [[slot, wh] sorted by slot, cost in millicents (sum wh*price), unmet wh]. need_wh<=0 or max_w<=0 returns [[], 0, max(need_wh,0)].

split: open-access


prompt:
The plan delivers more energy than requested and bills the overshoot.

prices[i] is the tariff in cents/kWh of 15-minute slot i. The car is present for slots arrive..depart-1 (depart exclusive) clipped to the tariff horizon; arrive may be negative. Each slot delivers at most max_w//4 Wh. Fill the cheapest slots first (equal price: earlier slot first), the last slot partially. Return [[slot, wh] sorted by slot, cost in millicents (sum wh*price), unmet wh]. need_wh<=0 or max_w<=0 returns [[], 0, max(need_wh,0)].

split: open-access


prompt:
Plans list extra slots with zero energy after the request is already satisfied.

prices[i] is the tariff in cents/kWh of 15-minute slot i. The car is present for slots arrive..depart-1 (depart exclusive) clipped to the tariff horizon; arrive may be negative. Each slot delivers at most max_w//4 Wh. Fill the cheapest slots first (equal price: earlier slot first), the last slot partially. Return [[slot, wh] sorted by slot, cost in millicents (sum wh*price), unmet wh]. need_wh<=0 or max_w<=0 returns [[], 0, max(need_wh,0)].

split: open-access


prompt:
A car that plugged in before the tariff horizon is planned into slots at the end of the day.

prices[i] is the tariff in cents/kWh of 15-minute slot i. The car is present for slots arrive..depart-1 (depart exclusive) clipped to the tariff horizon; arrive may be negative. Each slot delivers at most max_w//4 Wh. Fill the cheapest slots first (equal price: earlier slot first), the last slot partially. Return [[slot, wh] sorted by slot, cost in millicents (sum wh*price), unmet wh]. need_wh<=0 or max_w<=0 returns [[], 0, max(need_wh,0)].

split: open-access


prompt:
The quoted cost does not match the tariff of the slots listed in the plan.

prices[i] is the tariff in cents/kWh of 15-minute slot i. The car is present for slots arrive..depart-1 (depart exclusive) clipped to the tariff horizon; arrive may be negative. Each slot delivers at most max_w//4 Wh. Fill the cheapest slots first (equal price: earlier slot first), the last slot partially. Return [[slot, wh] sorted by slot, cost in millicents (sum wh*price), unmet wh]. need_wh<=0 or max_w<=0 returns [[], 0, max(need_wh,0)].

split: open-access


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

N = 1
observations = []
def solve(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = plug + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m < 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [267, 472, 501, 15, 5, None, 10], [14, 10]],
  ['regression: grace anchor (partial repair)', [1210, 1288, 1405, 30, 40, None, 5], [2, 40]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [1177, 1392, 1440, 15, 5, 300, 10], [0, 0]],
  ['regression: grace anchor (partial repair)', [935, 1103, 1359, 15, 25, 0, 15], [202, 0]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [1262, 1395, 1440, 0, 40, None, 5], [0, 0]],
  ['regression: grace anchor (partial repair)', [1142, 1227, 1440, 10, 25, 0, 1], [83, 0]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [240, 384, 858, 0, 40, None, 15], [474, 1280]],
  ['regression: grace anchor (partial repair)', [306, 373, 739, 10, 25, None, 10], [356, 900]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [1177, 1189, 1440, 15, 5, 1000, 5], [116, 120]],
  ['regression: grace anchor (partial repair)', [808, 1193, 1387, 15, 5, None, 1], [112, 560]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = plug + grace if plug + grace > done else done
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m < 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [267, 472, 501, 15, 5, None, 10], [14, 10]],
  ['regression: grace anchor (partial repair)', [1210, 1288, 1405, 30, 40, None, 5], [2, 40]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [1177, 1392, 1440, 15, 5, 300, 10], [0, 0]],
  ['regression: grace anchor (partial repair)', [935, 1103, 1359, 15, 25, 0, 15], [202, 0]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [1262, 1395, 1440, 0, 40, None, 5], [0, 0]],
  ['regression: grace anchor (partial repair)', [1142, 1227, 1440, 10, 25, 0, 1], [83, 0]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [240, 384, 858, 0, 40, None, 15], [474, 1280]],
  ['regression: grace anchor (partial repair)', [306, 373, 739, 10, 25, None, 10], [356, 900]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: grace anchor', [1177, 1189, 1440, 15, 5, 1000, 5], [116, 120]],
  ['regression: grace anchor (partial repair)', [808, 1193, 1387, 15, 5, None, 1], [112, 560]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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:
Drivers are billed idle time for minutes during which the car was still charging.

Times are minutes 0..1440 of one day. done is when charging finished (None: never finished, no idle fee). Idle time starts at done+grace and ends at unplug (exclusive). Only minutes in [360, 1320) are billable (night waiver). Fee = ceil(billable/block)*rate cents, then capped at cap when cap is not None (cap 0 waives the fee). Return [billable minutes, fee].

split: open-access


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

N = 1
observations = []
def solve(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m < 1320:
            billable += 1
    blocks = billable // block
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [267, 472, 501, 15, 5, None, 10], [14, 10]],
  ['regression: block rounding (partial repair)', [1210, 1288, 1405, 30, 40, None, 5], [2, 40]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [11, 183, 646, 10, 40, 1000, 15], [286, 800]],
  ['regression: block rounding (partial repair)', [797, 925, 1320, 10, 25, 1000, 10], [385, 975]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [649, 977, 1118, 10, 5, 1000, 10], [131, 70]],
  ['regression: block rounding (partial repair)', [839, 991, 1013, 15, 25, 1000, 5], [7, 50]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [37, 320, 601, 10, 5, None, 10], [241, 125]],
  ['regression: block rounding (partial repair)', [349, 571, 753, 30, 5, 300, 5], [152, 155]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [1177, 1189, 1440, 15, 5, 1000, 5], [116, 120]],
  ['regression: block rounding (partial repair)', [334, 705, 791, 30, 25, 1000, 5], [56, 300]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m < 1320:
            billable += 1
    blocks = round(billable / block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [267, 472, 501, 15, 5, None, 10], [14, 10]],
  ['regression: block rounding (partial repair)', [1210, 1288, 1405, 30, 40, None, 5], [2, 40]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [11, 183, 646, 10, 40, 1000, 15], [286, 800]],
  ['regression: block rounding (partial repair)', [797, 925, 1320, 10, 25, 1000, 10], [385, 975]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [649, 977, 1118, 10, 5, 1000, 10], [131, 70]],
  ['regression: block rounding (partial repair)', [839, 991, 1013, 15, 25, 1000, 5], [7, 50]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [37, 320, 601, 10, 5, None, 10], [241, 125]],
  ['regression: block rounding (partial repair)', [349, 571, 753, 30, 5, 300, 5], [152, 155]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: block rounding', [1177, 1189, 1440, 15, 5, 1000, 5], [116, 120]],
  ['regression: block rounding (partial repair)', [334, 705, 791, 30, 25, 1000, 5], [56, 300]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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:
Idle minutes shorter than a full block are never billed.

Times are minutes 0..1440 of one day. done is when charging finished (None: never finished, no idle fee). Idle time starts at done+grace and ends at unplug (exclusive). Only minutes in [360, 1320) are billable (night waiver). Fee = ceil(billable/block)*rate cents, then capped at cap when cap is not None (cap 0 waives the fee). Return [billable minutes, fee].

split: open-access


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

N = 1
observations = []
def solve(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 < m <= 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [745, 831, 1323, 0, 40, 1000, 10], [489, 1000]],
  ['regression: night waiver window edges (partial repair)', [1210, 1288, 1405, 30, 40, None, 5],
   [2, 40]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [935, 1103, 1359, 15, 25, 0, 15], [202, 0]],
  ['regression: night waiver window edges (partial repair)', [937, 1179, 1382, 15, 40, None, 1],
   [126, 5040]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [1142, 1227, 1440, 10, 25, 0, 1], [83, 0]],
  ['regression: night waiver window edges (partial repair)', [1042, 1241, 1388, 10, 25, 1000, 10],
   [69, 175]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [37, 320, 601, 10, 5, None, 10], [241, 125]],
  ['regression: night waiver window edges (partial repair)', [926, 1191, 1440, 15, 25, None, 15],
   [114, 200]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [1177, 1189, 1440, 15, 5, 1000, 5], [116, 120]],
  ['regression: night waiver window edges (partial repair)', [808, 1193, 1387, 15, 5, None, 1],
   [112, 560]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m <= 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [745, 831, 1323, 0, 40, 1000, 10], [489, 1000]],
  ['regression: night waiver window edges (partial repair)', [1210, 1288, 1405, 30, 40, None, 5],
   [2, 40]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [935, 1103, 1359, 15, 25, 0, 15], [202, 0]],
  ['regression: night waiver window edges (partial repair)', [937, 1179, 1382, 15, 40, None, 1],
   [126, 5040]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [1142, 1227, 1440, 10, 25, 0, 1], [83, 0]],
  ['regression: night waiver window edges (partial repair)', [1042, 1241, 1388, 10, 25, 1000, 10],
   [69, 175]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [37, 320, 601, 10, 5, None, 10], [241, 125]],
  ['regression: night waiver window edges (partial repair)', [926, 1191, 1440, 15, 25, None, 15],
   [114, 200]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: night waiver window edges', [1177, 1189, 1440, 15, 5, 1000, 5], [116, 120]],
  ['regression: night waiver window edges (partial repair)', [808, 1193, 1387, 15, 5, None, 1],
   [112, 560]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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:
The first billable morning minute is waived and the first night minute is billed.

Times are minutes 0..1440 of one day. done is when charging finished (None: never finished, no idle fee). Idle time starts at done+grace and ends at unplug (exclusive). Only minutes in [360, 1320) are billable (night waiver). Fee = ceil(billable/block)*rate cents, then capped at cap when cap is not None (cap 0 waives the fee). Return [billable minutes, fee].

split: open-access


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

N = 1
observations = []
def solve(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m < 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [694, 1094, 1440, 30, 5, 0, 5], [196, 0]],
  ['regression: zero cap waiver (partial repair)', [576, 671, 855, 15, 40, 0, 5], [169, 0]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [935, 1103, 1359, 15, 25, 0, 15], [202, 0]],
  ['regression: zero cap waiver (partial repair)', [370, 402, 585, 15, 5, 0, 5], [168, 0]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [1142, 1227, 1440, 10, 25, 0, 1], [83, 0]],
  ['regression: zero cap waiver (partial repair)', [335, 562, 733, 10, 40, 0, 15], [161, 0]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [786, 1147, 1171, 15, 40, 0, 5], [9, 0]],
  ['regression: zero cap waiver (partial repair)', [278, 314, 487, 30, 5, 0, 15], [127, 0]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [1260, 1286, 1440, 0, 40, 0, 10], [34, 0]],
  ['regression: zero cap waiver (partial repair)', [548, 763, 1064, 10, 5, 0, 15], [291, 0]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m < 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None and cap > 0:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [694, 1094, 1440, 30, 5, 0, 5], [196, 0]],
  ['regression: zero cap waiver (partial repair)', [576, 671, 855, 15, 40, 0, 5], [169, 0]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [935, 1103, 1359, 15, 25, 0, 15], [202, 0]],
  ['regression: zero cap waiver (partial repair)', [370, 402, 585, 15, 5, 0, 5], [168, 0]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [1142, 1227, 1440, 10, 25, 0, 1], [83, 0]],
  ['regression: zero cap waiver (partial repair)', [335, 562, 733, 10, 40, 0, 15], [161, 0]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [786, 1147, 1171, 15, 40, 0, 5], [9, 0]],
  ['regression: zero cap waiver (partial repair)', [278, 314, 487, 30, 5, 0, 15], [127, 0]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: zero cap waiver', [1260, 1286, 1440, 0, 40, 0, 10], [34, 0]],
  ['regression: zero cap waiver (partial repair)', [548, 763, 1064, 10, 5, 0, 15], [291, 0]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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:
A site configured to waive idle fees (cap 0) still bills them.

Times are minutes 0..1440 of one day. done is when charging finished (None: never finished, no idle fee). Idle time starts at done+grace and ends at unplug (exclusive). Only minutes in [360, 1320) are billable (night waiver). Fee = ceil(billable/block)*rate cents, then capped at cap when cap is not None (cap 0 waives the fee). Return [billable minutes, fee].

split: open-access


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

N = 1
observations = []
def solve(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug + 1):
        if 360 <= m < 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [267, 472, 501, 15, 5, None, 10], [14, 10]],
  ['regression: unplug minute exclusivity (partial repair)', [745, 831, 1323, 0, 40, 1000, 10],
   [489, 1000]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [11, 183, 646, 10, 40, 1000, 15], [286, 800]],
  ['regression: unplug minute exclusivity (partial repair)', [935, 1103, 1359, 15, 25, 0, 15],
   [202, 0]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [768, 1112, 1161, 10, 25, 300, 1], [39, 300]],
  ['regression: unplug minute exclusivity (partial repair)', [1142, 1227, 1440, 10, 25, 0, 1],
   [83, 0]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [37, 320, 601, 10, 5, None, 10], [241, 125]],
  ['regression: unplug minute exclusivity (partial repair)', [278, 314, 487, 30, 5, 0, 15],
   [127, 0]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [703, 737, 1228, 0, 25, 1000, 15], [491, 825]],
  ['regression: unplug minute exclusivity (partial repair)', [1177, 1189, 1440, 15, 5, 1000, 5],
   [116, 120]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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(plug, done, unplug, grace, rate, cap, block):
    if done is None or unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start + 1, unplug + 1):
        if 360 <= m < 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [267, 472, 501, 15, 5, None, 10], [14, 10]],
  ['regression: unplug minute exclusivity (partial repair)', [745, 831, 1323, 0, 40, 1000, 10],
   [489, 1000]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [11, 183, 646, 10, 40, 1000, 15], [286, 800]],
  ['regression: unplug minute exclusivity (partial repair)', [935, 1103, 1359, 15, 25, 0, 15],
   [202, 0]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [768, 1112, 1161, 10, 25, 300, 1], [39, 300]],
  ['regression: unplug minute exclusivity (partial repair)', [1142, 1227, 1440, 10, 25, 0, 1],
   [83, 0]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [37, 320, 601, 10, 5, None, 10], [241, 125]],
  ['regression: unplug minute exclusivity (partial repair)', [278, 314, 487, 30, 5, 0, 15],
   [127, 0]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unplug minute exclusivity', [703, 737, 1228, 0, 25, 1000, 15], [491, 825]],
  ['regression: unplug minute exclusivity (partial repair)', [1177, 1189, 1440, 15, 5, 1000, 5],
   [116, 120]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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:
Every idle session is billed one extra minute.

Times are minutes 0..1440 of one day. done is when charging finished (None: never finished, no idle fee). Idle time starts at done+grace and ends at unplug (exclusive). Only minutes in [360, 1320) are billable (night waiver). Fee = ceil(billable/block)*rate cents, then capped at cap when cap is not None (cap 0 waives the fee). Return [billable minutes, fee].

split: open-access


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

N = 1
observations = []
def solve(plug, done, unplug, grace, rate, cap, block):
    done = plug if done is None else done
    if unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m < 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [1028, None, 1141, 10, 25, None, 1], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [944, None, 1413, 10, 5, None, 5],
   [0, 0]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [865, None, 934, 30, 40, None, 5], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [994, None, 1274, 0, 25, 300, 1],
   [0, 0]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [1105, None, 1257, 0, 40, None, 1], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [1005, None, 1404, 0, 25, None, 1],
   [0, 0]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [527, None, 794, 0, 40, None, 5], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [408, None, 653, 10, 40, 1000, 5],
   [0, 0]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [365, None, 438, 15, 40, 1000, 15], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [768, None, 1112, 30, 25, None, 15],
   [0, 0]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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(plug, done, unplug, grace, rate, cap, block):
    done = (plug + unplug) // 2 if done is None else done
    if unplug <= done:
        return [0, 0]
    start = done + grace
    if unplug <= start:
        return [0, 0]
    billable = 0
    for m in range(start, unplug):
        if 360 <= m < 1320:
            billable += 1
    blocks = -(-billable // block)
    fee = blocks * rate
    if cap is not None:
        fee = min(fee, cap)
    return [billable, fee]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [1028, None, 1141, 10, 25, None, 1], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [944, None, 1413, 10, 5, None, 5],
   [0, 0]],
  ['control 1', [708, 712, 1012, 15, 25, 1000, 5], [285, 1000]],
  ['control 2', [424, 721, 1119, 10, 5, None, 15], [388, 130]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [865, None, 934, 30, 40, None, 5], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [994, None, 1274, 0, 25, 300, 1],
   [0, 0]],
  ['control 1', [1149, 1440, 1440, 0, 25, None, 1], [0, 0]],
  ['control 2', [421, 583, 815, 15, 5, 300, 15], [217, 75]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [1105, None, 1257, 0, 40, None, 1], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [1005, None, 1404, 0, 25, None, 1],
   [0, 0]],
  ['control 1', [1122, 1422, 1434, 10, 25, 0, 10], [0, 0]],
  ['control 2', [325, 596, 781, 30, 25, None, 15], [155, 275]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [527, None, 794, 0, 40, None, 5], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [408, None, 653, 10, 40, 1000, 5],
   [0, 0]],
  ['control 1', [887, 906, 899, 15, 5, 1000, 10], [0, 0]],
  ['control 2', [684, 849, 1335, 30, 25, 1000, 10], [441, 1000]]],
 [['boundary: unplugged inside grace', [600, 700, 710, 15, 25, None, 5], [0, 0]],
  ['boundary: never finished', [600, None, 900, 0, 25, None, 5], [0, 0]],
  ['boundary: idle crosses night waiver', [1200, 1300, 1400, 0, 10, None, 1], [20, 200]],
  ['regression: unfinished session handling', [365, None, 438, 15, 40, 1000, 15], [0, 0]],
  ['regression: unfinished session handling (partial repair)', [768, None, 1112, 30, 25, None, 15],
   [0, 0]],
  ['control 1', [942, 1011, 983, 15, 25, 300, 10], [0, 0]],
  ['control 2', [306, 373, 739, 10, 25, None, 10], [356, 900]]]]
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:
Sessions that never finished charging are charged an idle fee.

Times are minutes 0..1440 of one day. done is when charging finished (None: never finished, no idle fee). Idle time starts at done+grace and ends at unplug (exclusive). Only minutes in [360, 1320) are billable (night waiver). Fee = ceil(billable/block)*rate cents, then capped at cap when cap is not None (cap 0 waives the fee). Return [billable minutes, fee].

split: open-access