FA-73611 / Rate limiter algorithms / Open access
Escalating failure penalty box: failure log survives the ban · case 01
The first failure after a ban immediately triggers another, longer ban.
ROOT CAUSE
The failure log is not cleared when a ban starts.
VERIFIED REPAIR
Clear the failure log when banning.
Unsuccessful approach: Keeping the triggering failure still carries one strike into the next 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
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', 'ban-until-32', 'banned', 'banned', 'banned', 'ok'] | ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok'] | Failed |
| 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', 'ban-until-63'] | ['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', 'ban-until-17', 'banned', 'banned'] | ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok'] | Failed |
| banned failures ignored | ['fail', 'ban-until-11', 'banned', 'banned', 'ban-until-31', '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', '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 / 95aaeae042700341e56300a431a7a428e44c2fb3d09d7477d783a8607d419afe
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:
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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| ban and escalate | ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'ban-until-33', 'banned', 'banned', 'ok'] | ['fail', 'fail', 'ban-until-12', 'banned', 'fail', 'fail', 'ban-until-34', 'banned', 'ok'] | Failed |
| 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', 'ban-until-63'] | ['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', 'fail', 'ban-until-19', 'banned'] | ['fail', 'fail', 'ban-until-7', 'fail', 'fail', 'ok'] | Failed |
| banned failures ignored | ['fail', 'ban-until-11', 'banned', 'banned', 'ban-until-31', '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', '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 / caef49d5d36a634630c8d9ebb5b1f748686d6511e6eb50aff46f5738829b94d6
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.181917+00:00.
Case digest / 0ea517f212a870c90277c7e0856568d39d7587e2401886c90ef242e85fea51f1