FA-73601 / Rate limiter algorithms / Open access
Escalating failure penalty box: ban still active at its end instant · case 01
A client retrying exactly when told the ban ends is still refused.
ROOT CAUSE
The ban check uses t <= end.
VERIFIED REPAIR
Lift the ban at t == end.
Unsuccessful approach: Measuring the ban from its end time extends every ban by another base period.
Case contract
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.
Why this case matters
Login and abuse throttles escalate bans after repeated failures; window, escalation and log-reset rules decide whether attackers are slowed and legitimate users recover.
1 / The failure
Exit 1"""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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| ban and escalate | ['fail', 'fail', 'ban-until-12', 'banned', 'banned', 'fail', 'fail', 'ban-until-51', 'banned'] | ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok'] | Failed |
| third ban escalates | ['ban-until-10', 'banned', 'ban-until-50', 'ok', 'ok'] | ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok'] | Failed |
| ban end instant | ['fail', 'ban-until-21', 'banned', 'banned', 'fail'] | ['fail', 'ban-until-21', 'banned', 'ok', 'fail'] | Failed |
| window prune boundary | ['fail', 'fail', 'ban-until-17', 'fail'] | ['fail', 'fail', 'ban-until-17', 'fail'] | Passed |
| failures cleared by ban | ['fail', 'fail', 'ban-until-7', 'banned', 'fail', 'ok'] | ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok'] | Failed |
| banned failures ignored | ['fail', 'ban-until-11', 'banned', 'banned', 'banned', 'ok'] | ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok'] | Failed |
| random attempts | ['fail', 'fail', 'ban-until-31', 'banned', 'fail', 'fail', 'ban-until-87', 'banned', 'banned', 'banned', 'fail', 'ok', 'fail', 'ok'] | ['fail', 'fail', 'ban-until-31', 'banned', 'fail', 'fail', 'ban-until-87', 'banned', 'banned', 'fail', 'fail', 'ok', 'fail', 'ok'] | Failed |
SHA-256 / 42fd5ccfefaf9692a865f2f6c855f4e014a09290057417afdb9daa09d3475eb2
2 / The unsuccessful fix
Exit 1"""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 < base:
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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| ban and escalate | ['fail', 'fail', 'ban-until-12', 'banned', 'banned', 'banned', 'banned', 'fail', 'ok'] | ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok'] | Failed |
| third ban escalates | ['ban-until-10', 'banned', 'ban-until-50', 'ok', 'ok'] | ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok'] | Failed |
| ban end instant | ['fail', 'ban-until-21', 'banned', 'banned', 'banned'] | ['fail', 'ban-until-21', 'banned', 'ok', 'fail'] | Failed |
| window prune boundary | ['fail', 'fail', 'ban-until-17', 'fail'] | ['fail', 'fail', 'ban-until-17', 'fail'] | Passed |
| failures cleared by ban | ['fail', 'fail', 'ban-until-7', 'banned', 'banned', 'banned'] | ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok'] | Failed |
| banned failures ignored | ['fail', 'ban-until-11', 'banned', 'banned', 'banned', 'banned'] | ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok'] | Failed |
| random attempts | ['fail', 'fail', 'ban-until-31', 'banned', 'fail', 'fail', 'ban-until-87', 'banned', 'banned', 'banned', 'fail', 'ok', 'fail', 'ok'] | ['fail', 'fail', 'ban-until-31', 'banned', 'fail', 'fail', 'ban-until-87', 'banned', 'banned', 'fail', 'fail', 'ok', 'fail', 'ok'] | Failed |
SHA-256 / cbd0ec44c57cb1d2f612d743b941fdcf47757fab710254c9296add38150f7352
3 / The verified repair
Exit 0"""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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| ban and escalate | ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok'] | ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok'] | Passed |
| third ban escalates | ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok'] | ['ban-until-10', 'ban-until-30', 'ban-until-70', 'banned', 'ok'] | Passed |
| ban end instant | ['fail', 'ban-until-21', 'banned', 'ok', 'fail'] | ['fail', 'ban-until-21', 'banned', 'ok', 'fail'] | Passed |
| window prune boundary | ['fail', 'fail', 'ban-until-17', 'fail'] | ['fail', 'fail', 'ban-until-17', 'fail'] | Passed |
| failures cleared by ban | ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok'] | ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok'] | Passed |
| banned failures ignored | ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok'] | ['fail', 'ban-until-11', 'banned', 'banned', 'fail', 'ok'] | Passed |
| random attempts | ['fail', 'fail', 'ban-until-31', 'banned', 'fail', 'fail', 'ban-until-87', 'banned', 'banned', 'fail', 'fail', 'ok', 'fail', 'ok'] | ['fail', 'fail', 'ban-until-31', 'banned', 'fail', 'fail', 'ban-until-87', 'banned', 'banned', 'fail', 'fail', 'ok', 'fail', 'ok'] | Passed |
SHA-256 / a85b760b01d176918edfe5266592a16ed76089f21492a4e80dce604d33d858da
Verification & scope
A deterministic, bounded teaching model with stipulated constants and pre-hashed or explicitly hashed inputs; it is not a production implementation and makes no claim of conformance to any library or paper beyond the stated contract. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:48:49.095248+00:00.
Case digest / 58ab7d23a8f2dd3d3cc94fb7e0ea1c65eb31cf3ecde62ea436bb75bf950b2699