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

N = 1
observations = []
def solve(x):
    th = x['threshold']
    Wn = x['window_s']
    base = x['ban_s']
    fails = []
    until = None
    strikes = 0
    out = []
    for t, ok in x['events']:
        if until is not None and t < until:
            out.append('banned')
            continue
        if ok:
            out.append('ok')
            continue
        fails = [f for f in fails if f > t - Wn] + [t]
        if len(fails) >= th:
            until = t + base * 2 ** (strikes + 1)
            strikes += 1
            fails = []
            out.append('ban-until-%d' % until)
        else:
            out.append('fail')
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [31, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [71, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [23, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [12, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-17', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [9, False], [10, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [13, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[10, False],
               [13, False],
               [16, False],
               [20, False],
               [52, False],
               [53, False],
               [57, False],
               [74, False],
               [80, False],
               [87, False],
               [106, False],
               [115, True],
               [116, False],
               [119, True]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-31',
    'banned',
    'fail',
    'fail',
    'ban-until-87',
    'banned',
    'banned',
    'fail',
    'fail',
    'ok',
    'fail',
    'ok']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [32, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [72, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [24, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [13, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-18', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [10, False], [11, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [14, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[0, False],
               [23, False],
               [25, True],
               [34, False],
               [35, False],
               [49, False],
               [49, True],
               [60, False],
               [71, False],
               [83, False],
               [87, False],
               [87, False],
               [89, False],
               [117, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ok',
    'fail',
    'ban-until-50',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail',
    'ban-until-117',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [33, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [73, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [25, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [14, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-19', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [11, False], [12, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [15, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[8, False],
               [30, False],
               [30, False],
               [39, True],
               [44, False],
               [45, True],
               [47, False],
               [58, True],
               [78, False],
               [78, False],
               [82, False],
               [90, False],
               [107, False],
               [119, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'fail',
    'ok',
    'ban-until-59',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'ban-until-112',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [34, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [74, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [26, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [15, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-20', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [12, False], [13, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [16, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[6, False],
               [17, False],
               [25, False],
               [51, False],
               [52, True],
               [68, True],
               [78, True],
               [79, False],
               [86, True],
               [90, False],
               [92, True],
               [96, False],
               [100, False],
               [110, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-40',
    'fail',
    'ok',
    'ok',
    'ok',
    'fail',
    'ok',
    'fail',
    'ok',
    'ban-until-126',
    'banned',
    'banned']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [35, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [75, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [27, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [16, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-21', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [13, False], [14, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [17, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[11, True],
               [15, True],
               [29, False],
               [39, False],
               [45, False],
               [45, False],
               [46, False],
               [50, True],
               [54, False],
               [56, False],
               [58, True],
               [60, False],
               [83, False],
               [92, False]],
    'threshold': 3,
    'window_s': 20},
   ['ok',
    'ok',
    'fail',
    'fail',
    'ban-until-60',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail']]]]
for label, args, expected in cases[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(x):
    th = x['threshold']
    Wn = x['window_s']
    base = x['ban_s']
    fails = []
    until = None
    strikes = 0
    out = []
    for t, ok in x['events']:
        if until is not None and t < until:
            out.append('banned')
            continue
        if ok:
            out.append('ok')
            continue
        fails = [f for f in fails if f > t - Wn] + [t]
        if len(fails) >= th:
            until = t + base * (strikes + 1)
            strikes += 1
            fails = []
            out.append('ban-until-%d' % until)
        else:
            out.append('fail')
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [31, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [71, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [23, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [12, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-17', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [9, False], [10, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [13, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[10, False],
               [13, False],
               [16, False],
               [20, False],
               [52, False],
               [53, False],
               [57, False],
               [74, False],
               [80, False],
               [87, False],
               [106, False],
               [115, True],
               [116, False],
               [119, True]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-31',
    'banned',
    'fail',
    'fail',
    'ban-until-87',
    'banned',
    'banned',
    'fail',
    'fail',
    'ok',
    'fail',
    'ok']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [32, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [72, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [24, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [13, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-18', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [10, False], [11, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [14, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[0, False],
               [23, False],
               [25, True],
               [34, False],
               [35, False],
               [49, False],
               [49, True],
               [60, False],
               [71, False],
               [83, False],
               [87, False],
               [87, False],
               [89, False],
               [117, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ok',
    'fail',
    'ban-until-50',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail',
    'ban-until-117',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [33, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [73, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [25, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [14, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-19', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [11, False], [12, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [15, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[8, False],
               [30, False],
               [30, False],
               [39, True],
               [44, False],
               [45, True],
               [47, False],
               [58, True],
               [78, False],
               [78, False],
               [82, False],
               [90, False],
               [107, False],
               [119, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'fail',
    'ok',
    'ban-until-59',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'ban-until-112',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [34, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [74, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [26, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [15, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-20', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [12, False], [13, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [16, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[6, False],
               [17, False],
               [25, False],
               [51, False],
               [52, True],
               [68, True],
               [78, True],
               [79, False],
               [86, True],
               [90, False],
               [92, True],
               [96, False],
               [100, False],
               [110, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-40',
    'fail',
    'ok',
    'ok',
    'ok',
    'fail',
    'ok',
    'fail',
    'ok',
    'ban-until-126',
    'banned',
    'banned']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [35, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [75, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [27, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [16, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-21', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [13, False], [14, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [17, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[11, True],
               [15, True],
               [29, False],
               [39, False],
               [45, False],
               [45, False],
               [46, False],
               [50, True],
               [54, False],
               [56, False],
               [58, True],
               [60, False],
               [83, False],
               [92, False]],
    'threshold': 3,
    'window_s': 20},
   ['ok',
    'ok',
    'fail',
    'fail',
    'ban-until-60',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail']]]]
for label, args, expected in cases[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 offence is banned for twice the configured base duration.

Input {threshold, window_s, ban_s, events [[t, ok]]} with nondecreasing t. While t < ban end every event is "banned" and ignored. Failures are kept for window_s seconds (f > t - window_s). When the kept failures reach threshold the key is banned until t + ban_s * 2^strikes, strikes increments and the failure log is cleared; the event reports "ban-until-<end>". Otherwise failures report "fail" and successes "ok". Return the per-event results.

split: open-access


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

N = 1
observations = []
def solve(x):
    th = x['threshold']
    Wn = x['window_s']
    base = x['ban_s']
    fails = []
    until = None
    strikes = 0
    out = []
    for t, ok in x['events']:
        if until is not None and t < until:
            out.append('banned')
            continue
        if ok:
            out.append('ok')
            continue
        fails = [f for f in fails if f > t - Wn] + [t]
        if len(fails) >= th:
            until = t + base * 2 ** strikes
            strikes += 1
            out.append('ban-until-%d' % until)
        else:
            out.append('fail')
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [31, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [71, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [23, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [12, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-17', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [9, False], [10, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [13, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[10, False],
               [13, False],
               [16, False],
               [20, False],
               [52, False],
               [53, False],
               [57, False],
               [74, False],
               [80, False],
               [87, False],
               [106, False],
               [115, True],
               [116, False],
               [119, True]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-31',
    'banned',
    'fail',
    'fail',
    'ban-until-87',
    'banned',
    'banned',
    'fail',
    'fail',
    'ok',
    'fail',
    'ok']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [32, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [72, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [24, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [13, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-18', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [10, False], [11, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [14, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[0, False],
               [23, False],
               [25, True],
               [34, False],
               [35, False],
               [49, False],
               [49, True],
               [60, False],
               [71, False],
               [83, False],
               [87, False],
               [87, False],
               [89, False],
               [117, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ok',
    'fail',
    'ban-until-50',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail',
    'ban-until-117',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [33, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [73, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [25, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [14, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-19', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [11, False], [12, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [15, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[8, False],
               [30, False],
               [30, False],
               [39, True],
               [44, False],
               [45, True],
               [47, False],
               [58, True],
               [78, False],
               [78, False],
               [82, False],
               [90, False],
               [107, False],
               [119, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'fail',
    'ok',
    'ban-until-59',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'ban-until-112',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [34, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [74, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [26, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [15, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-20', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [12, False], [13, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [16, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[6, False],
               [17, False],
               [25, False],
               [51, False],
               [52, True],
               [68, True],
               [78, True],
               [79, False],
               [86, True],
               [90, False],
               [92, True],
               [96, False],
               [100, False],
               [110, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-40',
    'fail',
    'ok',
    'ok',
    'ok',
    'fail',
    'ok',
    'fail',
    'ok',
    'ban-until-126',
    'banned',
    'banned']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [35, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [75, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [27, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [16, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-21', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [13, False], [14, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [17, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[11, True],
               [15, True],
               [29, False],
               [39, False],
               [45, False],
               [45, False],
               [46, False],
               [50, True],
               [54, False],
               [56, False],
               [58, True],
               [60, False],
               [83, False],
               [92, False]],
    'threshold': 3,
    'window_s': 20},
   ['ok',
    'ok',
    'fail',
    'fail',
    'ban-until-60',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail']]]]
for label, args, expected in cases[N - 1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

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

N = 1
observations = []
def solve(x):
    th = x['threshold']
    Wn = x['window_s']
    base = x['ban_s']
    fails = []
    until = None
    strikes = 0
    out = []
    for t, ok in x['events']:
        if until is not None and t < until:
            out.append('banned')
            continue
        if ok:
            out.append('ok')
            continue
        fails = [f for f in fails if f > t - Wn] + [t]
        if len(fails) >= th:
            until = t + base * 2 ** strikes
            strikes += 1
            fails = fails[-1:]
            out.append('ban-until-%d' % until)
        else:
            out.append('fail')
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [31, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [71, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [23, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [12, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-17', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [9, False], [10, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [13, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[10, False],
               [13, False],
               [16, False],
               [20, False],
               [52, False],
               [53, False],
               [57, False],
               [74, False],
               [80, False],
               [87, False],
               [106, False],
               [115, True],
               [116, False],
               [119, True]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-31',
    'banned',
    'fail',
    'fail',
    'ban-until-87',
    'banned',
    'banned',
    'fail',
    'fail',
    'ok',
    'fail',
    'ok']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [32, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [72, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [24, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [13, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-18', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [10, False], [11, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [14, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[0, False],
               [23, False],
               [25, True],
               [34, False],
               [35, False],
               [49, False],
               [49, True],
               [60, False],
               [71, False],
               [83, False],
               [87, False],
               [87, False],
               [89, False],
               [117, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ok',
    'fail',
    'ban-until-50',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail',
    'ban-until-117',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [33, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [73, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [25, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [14, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-19', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [11, False], [12, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [15, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[8, False],
               [30, False],
               [30, False],
               [39, True],
               [44, False],
               [45, True],
               [47, False],
               [58, True],
               [78, False],
               [78, False],
               [82, False],
               [90, False],
               [107, False],
               [119, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'fail',
    'ok',
    'ban-until-59',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'ban-until-112',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [34, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [74, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [26, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [15, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-20', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [12, False], [13, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [16, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[6, False],
               [17, False],
               [25, False],
               [51, False],
               [52, True],
               [68, True],
               [78, True],
               [79, False],
               [86, True],
               [90, False],
               [92, True],
               [96, False],
               [100, False],
               [110, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-40',
    'fail',
    'ok',
    'ok',
    'ok',
    'fail',
    'ok',
    'fail',
    'ok',
    'ban-until-126',
    'banned',
    'banned']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [35, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [75, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [27, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [16, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-21', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [13, False], [14, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [17, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[11, True],
               [15, True],
               [29, False],
               [39, False],
               [45, False],
               [45, False],
               [46, False],
               [50, True],
               [54, False],
               [56, False],
               [58, True],
               [60, False],
               [83, False],
               [92, False]],
    'threshold': 3,
    'window_s': 20},
   ['ok',
    'ok',
    'fail',
    'fail',
    'ban-until-60',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail']]]]
for label, args, expected in cases[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 failure after a ban immediately triggers another, longer ban.

Input {threshold, window_s, ban_s, events [[t, ok]]} with nondecreasing t. While t < ban end every event is "banned" and ignored. Failures are kept for window_s seconds (f > t - window_s). When the kept failures reach threshold the key is banned until t + ban_s * 2^strikes, strikes increments and the failure log is cleared; the event reports "ban-until-<end>". Otherwise failures report "fail" and successes "ok". Return the per-event results.

split: open-access


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

N = 1
observations = []
def solve(x):
    th = x['threshold']
    Wn = x['window_s']
    base = x['ban_s']
    fails = []
    until = None
    strikes = 0
    out = []
    for t, ok in x['events']:
        if until is not None and t < until:
            out.append('banned')
            continue
        if ok:
            out.append('ok')
            continue
        fails = [f for f in fails if f >= t - Wn] + [t]
        if len(fails) >= th:
            until = t + base * 2 ** strikes
            strikes += 1
            fails = []
            out.append('ban-until-%d' % until)
        else:
            out.append('fail')
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [31, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [71, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [23, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [12, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-17', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [9, False], [10, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [13, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[10, False],
               [13, False],
               [16, False],
               [20, False],
               [52, False],
               [53, False],
               [57, False],
               [74, False],
               [80, False],
               [87, False],
               [106, False],
               [115, True],
               [116, False],
               [119, True]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-31',
    'banned',
    'fail',
    'fail',
    'ban-until-87',
    'banned',
    'banned',
    'fail',
    'fail',
    'ok',
    'fail',
    'ok']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [32, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [72, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [24, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [13, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-18', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [10, False], [11, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [14, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[0, False],
               [23, False],
               [25, True],
               [34, False],
               [35, False],
               [49, False],
               [49, True],
               [60, False],
               [71, False],
               [83, False],
               [87, False],
               [87, False],
               [89, False],
               [117, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ok',
    'fail',
    'ban-until-50',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail',
    'ban-until-117',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [33, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [73, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [25, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [14, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-19', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [11, False], [12, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [15, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[8, False],
               [30, False],
               [30, False],
               [39, True],
               [44, False],
               [45, True],
               [47, False],
               [58, True],
               [78, False],
               [78, False],
               [82, False],
               [90, False],
               [107, False],
               [119, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'fail',
    'ok',
    'ban-until-59',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'ban-until-112',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [34, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [74, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [26, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [15, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-20', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [12, False], [13, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [16, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[6, False],
               [17, False],
               [25, False],
               [51, False],
               [52, True],
               [68, True],
               [78, True],
               [79, False],
               [86, True],
               [90, False],
               [92, True],
               [96, False],
               [100, False],
               [110, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-40',
    'fail',
    'ok',
    'ok',
    'ok',
    'fail',
    'ok',
    'fail',
    'ok',
    'ban-until-126',
    'banned',
    'banned']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [35, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [75, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [27, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [16, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-21', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [13, False], [14, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [17, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[11, True],
               [15, True],
               [29, False],
               [39, False],
               [45, False],
               [45, False],
               [46, False],
               [50, True],
               [54, False],
               [56, False],
               [58, True],
               [60, False],
               [83, False],
               [92, False]],
    'threshold': 3,
    'window_s': 20},
   ['ok',
    'ok',
    'fail',
    'fail',
    'ban-until-60',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail']]]]
for label, args, expected in cases[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(x):
    th = x['threshold']
    Wn = x['window_s']
    base = x['ban_s']
    fails = []
    until = None
    strikes = 0
    out = []
    for t, ok in x['events']:
        if until is not None and t < until:
            out.append('banned')
            continue
        if ok:
            out.append('ok')
            continue
        fails = fails[-(th - 1):] + [t] if th > 1 else [t]
        if len(fails) >= th:
            until = t + base * 2 ** strikes
            strikes += 1
            fails = []
            out.append('ban-until-%d' % until)
        else:
            out.append('fail')
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [31, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [71, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [23, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [12, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-17', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [9, False], [10, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [13, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[10, False],
               [13, False],
               [16, False],
               [20, False],
               [52, False],
               [53, False],
               [57, False],
               [74, False],
               [80, False],
               [87, False],
               [106, False],
               [115, True],
               [116, False],
               [119, True]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-31',
    'banned',
    'fail',
    'fail',
    'ban-until-87',
    'banned',
    'banned',
    'fail',
    'fail',
    'ok',
    'fail',
    'ok']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [32, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [72, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [24, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [13, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-18', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [10, False], [11, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [14, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[0, False],
               [23, False],
               [25, True],
               [34, False],
               [35, False],
               [49, False],
               [49, True],
               [60, False],
               [71, False],
               [83, False],
               [87, False],
               [87, False],
               [89, False],
               [117, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ok',
    'fail',
    'ban-until-50',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail',
    'ban-until-117',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [33, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [73, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [25, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [14, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-19', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [11, False], [12, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [15, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[8, False],
               [30, False],
               [30, False],
               [39, True],
               [44, False],
               [45, True],
               [47, False],
               [58, True],
               [78, False],
               [78, False],
               [82, False],
               [90, False],
               [107, False],
               [119, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'fail',
    'ok',
    'ban-until-59',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'ban-until-112',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [34, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [74, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [26, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [15, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-20', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [12, False], [13, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [16, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[6, False],
               [17, False],
               [25, False],
               [51, False],
               [52, True],
               [68, True],
               [78, True],
               [79, False],
               [86, True],
               [90, False],
               [92, True],
               [96, False],
               [100, False],
               [110, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-40',
    'fail',
    'ok',
    'ok',
    'ok',
    'fail',
    'ok',
    'fail',
    'ok',
    'ban-until-126',
    'banned',
    'banned']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [35, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [75, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [27, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [16, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-21', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [13, False], [14, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [17, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[11, True],
               [15, True],
               [29, False],
               [39, False],
               [45, False],
               [45, False],
               [46, False],
               [50, True],
               [54, False],
               [56, False],
               [58, True],
               [60, False],
               [83, False],
               [92, False]],
    'threshold': 3,
    'window_s': 20},
   ['ok',
    'ok',
    'fail',
    'fail',
    'ban-until-60',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail']]]]
for label, args, expected in cases[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:
Two failures exactly one window apart trigger a ban.

Input {threshold, window_s, ban_s, events [[t, ok]]} with nondecreasing t. While t < ban end every event is "banned" and ignored. Failures are kept for window_s seconds (f > t - window_s). When the kept failures reach threshold the key is banned until t + ban_s * 2^strikes, strikes increments and the failure log is cleared; the event reports "ban-until-<end>". Otherwise failures report "fail" and successes "ok". Return the per-event results.

split: open-access


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

N = 1
observations = []
def solve(x):
    th = x['threshold']
    Wn = x['window_s']
    base = x['ban_s']
    fails = []
    until = None
    strikes = 0
    out = []
    for t, ok in x['events']:
        if until is not None and t < until:
            out.append('banned')
            if not ok:
                fails.append(t)
            continue
        if ok:
            out.append('ok')
            continue
        fails = [f for f in fails if f > t - Wn] + [t]
        if len(fails) >= th:
            until = t + base * 2 ** strikes
            strikes += 1
            fails = []
            out.append('ban-until-%d' % until)
        else:
            out.append('fail')
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [31, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [71, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [23, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [12, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-17', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [9, False], [10, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [13, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[10, False],
               [13, False],
               [16, False],
               [20, False],
               [52, False],
               [53, False],
               [57, False],
               [74, False],
               [80, False],
               [87, False],
               [106, False],
               [115, True],
               [116, False],
               [119, True]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-31',
    'banned',
    'fail',
    'fail',
    'ban-until-87',
    'banned',
    'banned',
    'fail',
    'fail',
    'ok',
    'fail',
    'ok']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [32, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [72, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [24, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [13, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-18', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [10, False], [11, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [14, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[0, False],
               [23, False],
               [25, True],
               [34, False],
               [35, False],
               [49, False],
               [49, True],
               [60, False],
               [71, False],
               [83, False],
               [87, False],
               [87, False],
               [89, False],
               [117, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ok',
    'fail',
    'ban-until-50',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail',
    'ban-until-117',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [33, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [73, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [25, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [14, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-19', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [11, False], [12, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [15, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[8, False],
               [30, False],
               [30, False],
               [39, True],
               [44, False],
               [45, True],
               [47, False],
               [58, True],
               [78, False],
               [78, False],
               [82, False],
               [90, False],
               [107, False],
               [119, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'fail',
    'ok',
    'ban-until-59',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'ban-until-112',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [34, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [74, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [26, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [15, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-20', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [12, False], [13, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [16, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[6, False],
               [17, False],
               [25, False],
               [51, False],
               [52, True],
               [68, True],
               [78, True],
               [79, False],
               [86, True],
               [90, False],
               [92, True],
               [96, False],
               [100, False],
               [110, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-40',
    'fail',
    'ok',
    'ok',
    'ok',
    'fail',
    'ok',
    'fail',
    'ok',
    'ban-until-126',
    'banned',
    'banned']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [35, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [75, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [27, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [16, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-21', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [13, False], [14, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [17, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[11, True],
               [15, True],
               [29, False],
               [39, False],
               [45, False],
               [45, False],
               [46, False],
               [50, True],
               [54, False],
               [56, False],
               [58, True],
               [60, False],
               [83, False],
               [92, False]],
    'threshold': 3,
    'window_s': 20},
   ['ok',
    'ok',
    'fail',
    'fail',
    'ban-until-60',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail']]]]
for label, args, expected in cases[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(x):
    th = x['threshold']
    Wn = x['window_s']
    base = x['ban_s']
    fails = []
    until = None
    strikes = 0
    out = []
    for t, ok in x['events']:
        if until is not None and t < until:
            out.append('banned')
            until = t + base
            continue
        if ok:
            out.append('ok')
            continue
        fails = [f for f in fails if f > t - Wn] + [t]
        if len(fails) >= th:
            until = t + base * 2 ** strikes
            strikes += 1
            fails = []
            out.append('ban-until-%d' % until)
        else:
            out.append('fail')
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [31, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [71, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [23, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [12, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-17', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [9, False], [10, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [13, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[10, False],
               [13, False],
               [16, False],
               [20, False],
               [52, False],
               [53, False],
               [57, False],
               [74, False],
               [80, False],
               [87, False],
               [106, False],
               [115, True],
               [116, False],
               [119, True]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-31',
    'banned',
    'fail',
    'fail',
    'ban-until-87',
    'banned',
    'banned',
    'fail',
    'fail',
    'ok',
    'fail',
    'ok']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [32, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [72, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [24, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [13, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-18', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [10, False], [11, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [14, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[0, False],
               [23, False],
               [25, True],
               [34, False],
               [35, False],
               [49, False],
               [49, True],
               [60, False],
               [71, False],
               [83, False],
               [87, False],
               [87, False],
               [89, False],
               [117, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ok',
    'fail',
    'ban-until-50',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail',
    'ban-until-117',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [33, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [73, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [25, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [14, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-19', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [11, False], [12, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [15, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[8, False],
               [30, False],
               [30, False],
               [39, True],
               [44, False],
               [45, True],
               [47, False],
               [58, True],
               [78, False],
               [78, False],
               [82, False],
               [90, False],
               [107, False],
               [119, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'fail',
    'ok',
    'ban-until-59',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'ban-until-112',
    'banned',
    'banned',
    'fail']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [34, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [74, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [26, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [15, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-20', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [12, False], [13, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [16, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[6, False],
               [17, False],
               [25, False],
               [51, False],
               [52, True],
               [68, True],
               [78, True],
               [79, False],
               [86, True],
               [90, False],
               [92, True],
               [96, False],
               [100, False],
               [110, False]],
    'threshold': 3,
    'window_s': 20},
   ['fail',
    'fail',
    'ban-until-40',
    'fail',
    'ok',
    'ok',
    'ok',
    'fail',
    'ok',
    'fail',
    'ok',
    'ban-until-126',
    'banned',
    'banned']]],
 [['ban and escalate',
   {'ban_s': 10,
    'events': [[0, False],
               [1, False],
               [2, False],
               [5, False],
               [12, False],
               [13, False],
               [14, False],
               [35, False],
               [40, True]],
    'threshold': 3,
    'window_s': 60},
   ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'fail', 'ok']],
  ['third ban escalates',
   {'ban_s': 10,
    'events': [[0, False], [10, False], [30, False], [65, True], [75, True]],
    'threshold': 1,
    'window_s': 5},
   ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok']],
  ['ban end instant',
   {'ban_s': 20,
    'events': [[0, False], [1, False], [20, True], [21, True], [27, False]],
    'threshold': 2,
    'window_s': 30},
   ['fail', 'ban-until-21', 'banned', 'ok', 'fail']],
  ['window prune boundary',
   {'ban_s': 5,
    'events': [[0, False], [10, False], [16, False], [30, False]],
    'threshold': 2,
    'window_s': 10},
   ['fail', 'fail', 'ban-until-21', 'fail']],
  ['failures cleared by ban',
   {'ban_s': 5,
    'events': [[0, False], [1, False], [2, False], [7, False], [13, False], [14, True]],
    'threshold': 3,
    'window_s': 100},
   ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok']],
  ['banned failures ignored',
   {'ban_s': 10,
    'events': [[0, False], [1, False], [5, False], [6, False], [11, False], [17, True]],
    'threshold': 2,
    'window_s': 100},
   ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok']],
  ['random attempts',
   {'ban_s': 15,
    'events': [[11, True],
               [15, True],
               [29, False],
               [39, False],
               [45, False],
               [45, False],
               [46, False],
               [50, True],
               [54, False],
               [56, False],
               [58, True],
               [60, False],
               [83, False],
               [92, False]],
    'threshold': 3,
    'window_s': 20},
   ['ok',
    'ok',
    'fail',
    'fail',
    'ban-until-60',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'banned',
    'fail',
    'fail',
    'fail']]]]
for label, args, expected in cases[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:
Attempts made while banned count toward the next ban.

Input {threshold, window_s, ban_s, events [[t, ok]]} with nondecreasing t. While t < ban end every event is "banned" and ignored. Failures are kept for window_s seconds (f > t - window_s). When the kept failures reach threshold the key is banned until t + ban_s * 2^strikes, strikes increments and the failure log is cleared; the event reports "ban-until-<end>". Otherwise failures report "fail" and successes "ok". Return the per-event results.

split: open-access