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

N = 1
observations = []
def solve(x):
    def rnd(n, d):
        q, r = divmod(n, d)
        return q + (1 if 2 * r >= d else 0)
    deadline = x['due_day'] + x['grace']
    paid = x['paid_day']
    short = x['payment_due'] - x['paid_amount']
    on_time = paid is not None and paid <= deadline and short <= x['tolerance']
    if on_time:
        return {'late': False, 'fee': 0, 'days_late': 0}
    end = paid if paid is not None else x['as_of']
    fee = rnd(x['payment_due'] * x['fee_bp'], 10000)
    fee = min(x['fee_max'], fee)
    return {'late': True, 'fee': fee, 'days_late': max(0, end - x['due_day'])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: fee floor', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 2500, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 0}], ['regression: fee floor, partial-repair probe', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 0}], ['control 1', {'due_day': 1, 'grace': 10, 'paid_day': 0, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': True, 'fee': 5000, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 0, 'paid_day': 18, 'payment_due': 100000, 'paid_amount': 2500, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 4000, 'days_late': 3}], ['control 3', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 0, 'paid_day': 8, 'payment_due': 150000, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 7500, 'days_late': 3}], ['control 5', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 800, 'days_late': 11}]], [['regression: fee floor', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 2500, 'days_late': 1}], ['regression: fee floor, partial-repair probe', {'due_day': 15, 'grace': 0, 'paid_day': 16, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 5000, 'days_late': 1}], ['control 1', {'due_day': 15, 'grace': 15, 'paid_day': 18, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 0, 'paid_day': 8, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 3}], ['control 5', {'due_day': 5, 'grace': 15, 'paid_day': 8, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: fee floor', {'due_day': 5, 'grace': 0, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 40}], ['regression: fee floor, partial-repair probe', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 5000, 'days_late': 11}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 0, 'paid_day': 14, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 10, 'paid_day': 5, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 4000, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: fee floor', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 0}], ['regression: fee floor, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': 8, 'payment_due': 150000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 3}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 6, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 100, 'days_late': 1}], ['control 2', {'due_day': 5, 'grace': 15, 'paid_day': 21, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 1000, 'days_late': 16}], ['control 3', {'due_day': 1, 'grace': 0, 'paid_day': 4, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 21}, {'late': True, 'fee': 125, 'days_late': 3}], ['control 4', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: fee floor', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 2500, 'days_late': 0}], ['regression: fee floor, partial-repair probe', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 150000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 5000, 'days_late': 0}], ['control 1', {'due_day': 5, 'grace': 10, 'paid_day': None, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 5000, 'days_late': 40}], ['control 2', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': True, 'fee': 4000, 'days_late': 1}], ['control 3', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 4000, 'days_late': 11}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 15, 'grace': 10, 'paid_day': 14, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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):
    def rnd(n, d):
        q, r = divmod(n, d)
        return q + (1 if 2 * r >= d else 0)
    deadline = x['due_day'] + x['grace']
    paid = x['paid_day']
    short = x['payment_due'] - x['paid_amount']
    on_time = paid is not None and paid <= deadline and short <= x['tolerance']
    if on_time:
        return {'late': False, 'fee': 0, 'days_late': 0}
    end = paid if paid is not None else x['as_of']
    fee = rnd(x['payment_due'] * x['fee_bp'], 10000)
    fee = max(x['fee_min'], fee)
    return {'late': True, 'fee': fee, 'days_late': max(0, end - x['due_day'])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: fee floor', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 2500, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 0}], ['regression: fee floor, partial-repair probe', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 0}], ['control 1', {'due_day': 1, 'grace': 10, 'paid_day': 0, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': True, 'fee': 5000, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 0, 'paid_day': 18, 'payment_due': 100000, 'paid_amount': 2500, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 4000, 'days_late': 3}], ['control 3', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 0, 'paid_day': 8, 'payment_due': 150000, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 7500, 'days_late': 3}], ['control 5', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 800, 'days_late': 11}]], [['regression: fee floor', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 2500, 'days_late': 1}], ['regression: fee floor, partial-repair probe', {'due_day': 15, 'grace': 0, 'paid_day': 16, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 5000, 'days_late': 1}], ['control 1', {'due_day': 15, 'grace': 15, 'paid_day': 18, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 0, 'paid_day': 8, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 3}], ['control 5', {'due_day': 5, 'grace': 15, 'paid_day': 8, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: fee floor', {'due_day': 5, 'grace': 0, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 40}], ['regression: fee floor, partial-repair probe', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 5000, 'days_late': 11}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 0, 'paid_day': 14, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 10, 'paid_day': 5, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 4000, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: fee floor', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 0}], ['regression: fee floor, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': 8, 'payment_due': 150000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 3}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 6, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 100, 'days_late': 1}], ['control 2', {'due_day': 5, 'grace': 15, 'paid_day': 21, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 1000, 'days_late': 16}], ['control 3', {'due_day': 1, 'grace': 0, 'paid_day': 4, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 21}, {'late': True, 'fee': 125, 'days_late': 3}], ['control 4', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: fee floor', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 2500, 'days_late': 0}], ['regression: fee floor, partial-repair probe', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 150000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 5000, 'days_late': 0}], ['control 1', {'due_day': 5, 'grace': 10, 'paid_day': None, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 5000, 'days_late': 40}], ['control 2', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': True, 'fee': 4000, 'days_late': 1}], ['control 3', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 4000, 'days_late': 11}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 15, 'grace': 10, 'paid_day': 14, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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:
Late fees on small payments fall below the contractual minimum.

x = {'due_day', 'grace', 'paid_day' or None, 'payment_due', 'paid_amount', 'tolerance', 'fee_bp', 'fee_min', 'fee_max', 'as_of'}. A payment is on time when paid_day is not None, paid_day <= due_day + grace and payment_due - paid_amount <= tolerance. Otherwise fee = clamp(round_half_up(payment_due*fee_bp/10000), fee_min, fee_max) and days_late = max(0, (paid_day or as_of when unpaid) - due_day). Return {'late', 'fee', 'days_late'}.

split: open-access


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

N = 1
observations = []
def solve(x):
    def rnd(n, d):
        q, r = divmod(n, d)
        return q + (1 if 2 * r >= d else 0)
    deadline = x['due_day'] + x['grace']
    paid = x['paid_day']
    short = x['payment_due'] - x['paid_amount']
    on_time = paid is not None and paid <= deadline and short <= x['tolerance']
    if on_time:
        return {'late': False, 'fee': 0, 'days_late': 0}
    end = x['as_of']
    fee = rnd(x['payment_due'] * x['fee_bp'], 10000)
    fee = max(x['fee_min'], min(fee, x['fee_max']))
    return {'late': True, 'fee': fee, 'days_late': max(0, end - x['due_day'])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: unpaid lateness end', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 0}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 1, 'grace': 15, 'paid_day': None, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 5000, 'days_late': 40}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 15, 'paid_day': 20, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 0, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 2500, 'days_late': 40}], ['control 5', {'due_day': 1, 'grace': 0, 'paid_day': 0, 'payment_due': 100000, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: unpaid lateness end', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 2500, 'days_late': 1}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 15, 'grace': 10, 'paid_day': None, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 55}, {'late': True, 'fee': 2500, 'days_late': 40}], ['control 1', {'due_day': 15, 'grace': 15, 'paid_day': 18, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 15, 'paid_day': 8, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: unpaid lateness end', {'due_day': 5, 'grace': 10, 'paid_day': 5, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 4000, 'days_late': 0}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 40}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 0, 'paid_day': 14, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 15, 'paid_day': 0, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: unpaid lateness end', {'due_day': 5, 'grace': 0, 'paid_day': 6, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 100, 'days_late': 1}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 5, 'grace': 15, 'paid_day': None, 'payment_due': 100000, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 20}], ['control 1', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 150000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: unpaid lateness end', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': True, 'fee': 4000, 'days_late': 1}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 5, 'grace': 10, 'paid_day': None, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 5000, 'days_late': 40}], ['control 1', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 10, 'paid_day': 14, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 15, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 40}], ['control 4', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 5, 'grace': 10, 'paid_day': None, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 1500, 'days_late': 20}]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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):
    def rnd(n, d):
        q, r = divmod(n, d)
        return q + (1 if 2 * r >= d else 0)
    deadline = x['due_day'] + x['grace']
    paid = x['paid_day']
    short = x['payment_due'] - x['paid_amount']
    on_time = paid is not None and paid <= deadline and short <= x['tolerance']
    if on_time:
        return {'late': False, 'fee': 0, 'days_late': 0}
    end = paid if paid is not None else deadline
    fee = rnd(x['payment_due'] * x['fee_bp'], 10000)
    fee = max(x['fee_min'], min(fee, x['fee_max']))
    return {'late': True, 'fee': fee, 'days_late': max(0, end - x['due_day'])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: unpaid lateness end', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 0}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 1, 'grace': 15, 'paid_day': None, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 5000, 'days_late': 40}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 15, 'paid_day': 20, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 0, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 2500, 'days_late': 40}], ['control 5', {'due_day': 1, 'grace': 0, 'paid_day': 0, 'payment_due': 100000, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: unpaid lateness end', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 2500, 'days_late': 1}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 15, 'grace': 10, 'paid_day': None, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 55}, {'late': True, 'fee': 2500, 'days_late': 40}], ['control 1', {'due_day': 15, 'grace': 15, 'paid_day': 18, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 5, 'grace': 15, 'paid_day': 8, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: unpaid lateness end', {'due_day': 5, 'grace': 10, 'paid_day': 5, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 4000, 'days_late': 0}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 40}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 0, 'paid_day': 14, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 15, 'paid_day': 0, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: unpaid lateness end', {'due_day': 5, 'grace': 0, 'paid_day': 6, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 100, 'days_late': 1}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 5, 'grace': 15, 'paid_day': None, 'payment_due': 100000, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 20}], ['control 1', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 150000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: unpaid lateness end', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': True, 'fee': 4000, 'days_late': 1}], ['regression: unpaid lateness end, partial-repair probe', {'due_day': 5, 'grace': 10, 'paid_day': None, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 5000, 'days_late': 40}], ['control 1', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 10, 'paid_day': 14, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 15, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 40}], ['control 4', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 5, 'grace': 10, 'paid_day': None, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 1500, 'days_late': 20}]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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:
Late payments report lateness up to the statement date instead of the payment date.

x = {'due_day', 'grace', 'paid_day' or None, 'payment_due', 'paid_amount', 'tolerance', 'fee_bp', 'fee_min', 'fee_max', 'as_of'}. A payment is on time when paid_day is not None, paid_day <= due_day + grace and payment_due - paid_amount <= tolerance. Otherwise fee = clamp(round_half_up(payment_due*fee_bp/10000), fee_min, fee_max) and days_late = max(0, (paid_day or as_of when unpaid) - due_day). Return {'late', 'fee', 'days_late'}.

split: open-access


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

N = 1
observations = []
def solve(x):
    def rnd(n, d):
        q, r = divmod(n, d)
        return q + (1 if 2 * r >= d else 0)
    deadline = x['due_day'] + x['grace']
    paid = x['paid_day']
    short = x['payment_due'] - x['paid_amount']
    on_time = paid is not None and paid <= deadline and short <= x['tolerance']
    if on_time:
        return {'late': False, 'fee': 0, 'days_late': 0}
    end = paid if paid is not None else x['as_of']
    fee = rnd(short * x['fee_bp'], 10000)
    fee = max(x['fee_min'], min(fee, x['fee_max']))
    return {'late': True, 'fee': fee, 'days_late': max(0, end - x['due_day'])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: fee base', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 0}], ['regression: fee base, partial-repair probe', {'due_day': 15, 'grace': 0, 'paid_day': 18, 'payment_due': 100000, 'paid_amount': 2500, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 4000, 'days_late': 3}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 2500, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 800, 'days_late': 11}], ['control 4', {'due_day': 15, 'grace': 10, 'paid_day': 18, 'payment_due': 100000, 'paid_amount': 0, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 35}, {'late': True, 'fee': 4000, 'days_late': 3}], ['control 5', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 11}]], [['regression: fee base', {'due_day': 15, 'grace': 0, 'paid_day': 16, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 5000, 'days_late': 1}], ['control 1', {'due_day': 15, 'grace': 15, 'paid_day': 18, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 2500, 'days_late': 1}], ['control 4', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 15, 'grace': 15, 'paid_day': 30, 'payment_due': 20000, 'paid_amount': 2500, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 55}, {'late': True, 'fee': 2500, 'days_late': 15}], ['control 6', {'due_day': 15, 'grace': 10, 'paid_day': None, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 55}, {'late': True, 'fee': 2500, 'days_late': 40}]], [['regression: fee base', {'due_day': 5, 'grace': 10, 'paid_day': 5, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 4000, 'days_late': 0}], ['regression: fee base, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 40}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 0, 'paid_day': 14, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 15, 'paid_day': 0, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: fee base', {'due_day': 5, 'grace': 15, 'paid_day': 21, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 1000, 'days_late': 16}], ['regression: fee base, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': 6, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 100, 'days_late': 1}], ['control 1', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 150000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 0}]], [['regression: fee base', {'due_day': 5, 'grace': 10, 'paid_day': None, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 5000, 'days_late': 40}], ['control 1', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 10, 'paid_day': 14, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 2500, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 15, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 40}], ['control 5', {'due_day': 15, 'grace': 15, 'paid_day': 31, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 55}, {'late': True, 'fee': 2500, 'days_late': 16}], ['control 6', {'due_day': 1, 'grace': 10, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 3}]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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):
    def rnd(n, d):
        q, r = divmod(n, d)
        return q + (1 if 2 * r >= d else 0)
    deadline = x['due_day'] + x['grace']
    paid = x['paid_day']
    short = x['payment_due'] - x['paid_amount']
    on_time = paid is not None and paid <= deadline and short <= x['tolerance']
    if on_time:
        return {'late': False, 'fee': 0, 'days_late': 0}
    end = paid if paid is not None else x['as_of']
    fee = rnd(x['paid_amount'] * x['fee_bp'], 10000)
    fee = max(x['fee_min'], min(fee, x['fee_max']))
    return {'late': True, 'fee': fee, 'days_late': max(0, end - x['due_day'])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: fee base', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 25}, {'late': True, 'fee': 5000, 'days_late': 0}], ['regression: fee base, partial-repair probe', {'due_day': 15, 'grace': 0, 'paid_day': 18, 'payment_due': 100000, 'paid_amount': 2500, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 4000, 'days_late': 3}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 2500, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 800, 'days_late': 11}], ['control 4', {'due_day': 15, 'grace': 10, 'paid_day': 18, 'payment_due': 100000, 'paid_amount': 0, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 35}, {'late': True, 'fee': 4000, 'days_late': 3}], ['control 5', {'due_day': 1, 'grace': 10, 'paid_day': 12, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 11}]], [['regression: fee base', {'due_day': 15, 'grace': 0, 'paid_day': 16, 'payment_due': 150000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 5000, 'days_late': 1}], ['control 1', {'due_day': 15, 'grace': 15, 'paid_day': 18, 'payment_due': 20000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 0, 'paid_day': 2, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 2500, 'days_late': 1}], ['control 4', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 15, 'grace': 15, 'paid_day': 30, 'payment_due': 20000, 'paid_amount': 2500, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 55}, {'late': True, 'fee': 2500, 'days_late': 15}], ['control 6', {'due_day': 15, 'grace': 10, 'paid_day': None, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 55}, {'late': True, 'fee': 2500, 'days_late': 40}]], [['regression: fee base', {'due_day': 5, 'grace': 10, 'paid_day': 5, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 25}, {'late': True, 'fee': 4000, 'days_late': 0}], ['regression: fee base, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 1500, 'days_late': 40}], ['control 1', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 0, 'paid_day': 14, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 2500, 'paid_amount': 150000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 15, 'paid_day': 0, 'payment_due': 2500, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}]], [['regression: fee base', {'due_day': 5, 'grace': 15, 'paid_day': 21, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 1000, 'days_late': 16}], ['regression: fee base, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': 6, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 45}, {'late': True, 'fee': 100, 'days_late': 1}], ['control 1', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 15, 'paid_day': 5, 'payment_due': 20000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 150000, 'paid_amount': 149990, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 21}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 5', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 0}]], [['regression: fee base', {'due_day': 5, 'grace': 10, 'paid_day': None, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 5000, 'days_late': 40}], ['control 1', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 100000, 'paid_amount': 149990, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 2', {'due_day': 15, 'grace': 10, 'paid_day': 14, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 5000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 3', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 2500, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 45}, {'late': True, 'fee': 2500, 'days_late': 0}], ['control 4', {'due_day': 1, 'grace': 15, 'paid_day': None, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 5000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 40}], ['control 5', {'due_day': 15, 'grace': 15, 'paid_day': 31, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 55}, {'late': True, 'fee': 2500, 'days_late': 16}], ['control 6', {'due_day': 1, 'grace': 10, 'paid_day': 4, 'payment_due': 20000, 'paid_amount': 0, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 41}, {'late': True, 'fee': 1500, 'days_late': 3}]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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:
Late but complete payments are charged only the minimum fee.

x = {'due_day', 'grace', 'paid_day' or None, 'payment_due', 'paid_amount', 'tolerance', 'fee_bp', 'fee_min', 'fee_max', 'as_of'}. A payment is on time when paid_day is not None, paid_day <= due_day + grace and payment_due - paid_amount <= tolerance. Otherwise fee = clamp(round_half_up(payment_due*fee_bp/10000), fee_min, fee_max) and days_late = max(0, (paid_day or as_of when unpaid) - due_day). Return {'late', 'fee', 'days_late'}.

split: open-access


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

N = 1
observations = []
def solve(x):
    rate = x['initial_bp']
    out = []
    life_max = x['initial_bp'] + x['lifetime_cap_bp']
    for i, idx in enumerate(x['index_path']):
        fi = idx + x['margin_bp']
        q, r = divmod(fi, x['round_to'])
        fi = (q + (1 if 2 * r >= x['round_to'] else 0)) * x['round_to']
        cap = x['initial_cap_bp'] if i == 1 else x['periodic_cap_bp']
        new = max(rate - cap, min(fi, rate + cap))
        new = max(x['floor_bp'], min(new, life_max))
        out.append(new)
        rate = new
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: first adjustment cap', {'initial_bp': 450, 'index_path': [250, 650, 100, 650, 650], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [475, 575, 475, 575, 675]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 500, 'index_path': [212, 100, 50, 250, 700], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 400, 400, 500, 600]], ['control 1', {'initial_bp': 300, 'index_path': [212, 212], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [475, 475]], ['control 2', {'initial_bp': 300, 'index_path': [100, 50, 250], 'margin_bp': 275, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [400, 350, 550]], ['control 3', {'initial_bp': 300, 'index_path': [400, 537], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 700]], ['control 4', {'initial_bp': 450, 'index_path': [50, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [300, 325]], ['control 5', {'initial_bp': 500, 'index_path': [700], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [700]]], [['regression: first adjustment cap', {'initial_bp': 450, 'index_path': [650, 50, 212], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [650, 550, 500]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 450, 'index_path': [212, 50, 250, 212, 700], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [450, 400, 500, 450, 650]], ['control 1', {'initial_bp': 500, 'index_path': [537, 650, 250, 400, 537], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [700, 875, 675, 625, 750]], ['control 2', {'initial_bp': 450, 'index_path': [250, 100, 700], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [475, 325, 525]], ['control 3', {'initial_bp': 450, 'index_path': [50], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [400]], ['control 4', {'initial_bp': 500, 'index_path': [212], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500]], ['control 5', {'initial_bp': 300, 'index_path': [250], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [475]]], [['regression: first adjustment cap', {'initial_bp': 300, 'index_path': [537, 700, 250], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [750, 850, 750]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 500, 'index_path': [212, 537], 'margin_bp': 275, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 700]], ['control 1', {'initial_bp': 450, 'index_path': [212, 650, 50, 650], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [500, 700, 500, 700]], ['control 2', {'initial_bp': 450, 'index_path': [250, 250, 212], 'margin_bp': 225, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 450]], ['control 3', {'initial_bp': 450, 'index_path': [100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400]], ['control 4', {'initial_bp': 300, 'index_path': [650], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500]], ['control 5', {'initial_bp': 500, 'index_path': [50, 250, 50, 250, 650], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400, 475, 400, 475, 675]]], [['regression: first adjustment cap', {'initial_bp': 450, 'index_path': [537, 250, 212, 212], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [650, 550, 450, 450]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 450, 'index_path': [100, 250, 650, 400], 'margin_bp': 225, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [350, 450, 550, 650]], ['control 1', {'initial_bp': 300, 'index_path': [650, 250, 50, 537, 50], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 375, 575, 375]], ['control 2', {'initial_bp': 300, 'index_path': [400, 400, 537], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 675, 800]], ['control 3', {'initial_bp': 500, 'index_path': [537], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [700]], ['control 4', {'initial_bp': 500, 'index_path': [100, 212, 100], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [350, 450, 350]], ['control 5', {'initial_bp': 450, 'index_path': [250, 50, 700], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 400, 500]]], [['regression: first adjustment cap', {'initial_bp': 450, 'index_path': [650], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [875]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 300, 'index_path': [50, 537, 250, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [300, 400, 475, 375]], ['control 1', {'initial_bp': 300, 'index_path': [400, 537, 100], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500, 700, 500]], ['control 2', {'initial_bp': 450, 'index_path': [400, 537], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [650, 775]], ['control 3', {'initial_bp': 300, 'index_path': [250], 'margin_bp': 225, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [500]], ['control 4', {'initial_bp': 300, 'index_path': [50, 50], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400, 400]], ['control 5', {'initial_bp': 450, 'index_path': [100, 250, 100, 650], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [375, 525, 375, 575]]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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):
    rate = x['initial_bp']
    out = []
    life_max = x['initial_bp'] + x['lifetime_cap_bp']
    for i, idx in enumerate(x['index_path']):
        fi = idx + x['margin_bp']
        q, r = divmod(fi, x['round_to'])
        fi = (q + (1 if 2 * r >= x['round_to'] else 0)) * x['round_to']
        cap = x['initial_cap_bp'] if rate == x['initial_bp'] else x['periodic_cap_bp']
        new = max(rate - cap, min(fi, rate + cap))
        new = max(x['floor_bp'], min(new, life_max))
        out.append(new)
        rate = new
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: first adjustment cap', {'initial_bp': 450, 'index_path': [250, 650, 100, 650, 650], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [475, 575, 475, 575, 675]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 500, 'index_path': [212, 100, 50, 250, 700], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 400, 400, 500, 600]], ['control 1', {'initial_bp': 300, 'index_path': [212, 212], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [475, 475]], ['control 2', {'initial_bp': 300, 'index_path': [100, 50, 250], 'margin_bp': 275, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [400, 350, 550]], ['control 3', {'initial_bp': 300, 'index_path': [400, 537], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 700]], ['control 4', {'initial_bp': 450, 'index_path': [50, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [300, 325]], ['control 5', {'initial_bp': 500, 'index_path': [700], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [700]]], [['regression: first adjustment cap', {'initial_bp': 450, 'index_path': [650, 50, 212], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [650, 550, 500]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 450, 'index_path': [212, 50, 250, 212, 700], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [450, 400, 500, 450, 650]], ['control 1', {'initial_bp': 500, 'index_path': [537, 650, 250, 400, 537], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [700, 875, 675, 625, 750]], ['control 2', {'initial_bp': 450, 'index_path': [250, 100, 700], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [475, 325, 525]], ['control 3', {'initial_bp': 450, 'index_path': [50], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [400]], ['control 4', {'initial_bp': 500, 'index_path': [212], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500]], ['control 5', {'initial_bp': 300, 'index_path': [250], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [475]]], [['regression: first adjustment cap', {'initial_bp': 300, 'index_path': [537, 700, 250], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [750, 850, 750]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 500, 'index_path': [212, 537], 'margin_bp': 275, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 700]], ['control 1', {'initial_bp': 450, 'index_path': [212, 650, 50, 650], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [500, 700, 500, 700]], ['control 2', {'initial_bp': 450, 'index_path': [250, 250, 212], 'margin_bp': 225, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 450]], ['control 3', {'initial_bp': 450, 'index_path': [100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400]], ['control 4', {'initial_bp': 300, 'index_path': [650], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500]], ['control 5', {'initial_bp': 500, 'index_path': [50, 250, 50, 250, 650], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400, 475, 400, 475, 675]]], [['regression: first adjustment cap', {'initial_bp': 450, 'index_path': [537, 250, 212, 212], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [650, 550, 450, 450]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 450, 'index_path': [100, 250, 650, 400], 'margin_bp': 225, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [350, 450, 550, 650]], ['control 1', {'initial_bp': 300, 'index_path': [650, 250, 50, 537, 50], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 375, 575, 375]], ['control 2', {'initial_bp': 300, 'index_path': [400, 400, 537], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 675, 800]], ['control 3', {'initial_bp': 500, 'index_path': [537], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [700]], ['control 4', {'initial_bp': 500, 'index_path': [100, 212, 100], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [350, 450, 350]], ['control 5', {'initial_bp': 450, 'index_path': [250, 50, 700], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 400, 500]]], [['regression: first adjustment cap', {'initial_bp': 450, 'index_path': [650], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [875]], ['regression: first adjustment cap, partial-repair probe', {'initial_bp': 300, 'index_path': [50, 537, 250, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [300, 400, 475, 375]], ['control 1', {'initial_bp': 300, 'index_path': [400, 537, 100], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500, 700, 500]], ['control 2', {'initial_bp': 450, 'index_path': [400, 537], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [650, 775]], ['control 3', {'initial_bp': 300, 'index_path': [250], 'margin_bp': 225, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [500]], ['control 4', {'initial_bp': 300, 'index_path': [50, 50], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400, 400]], ['control 5', {'initial_bp': 450, 'index_path': [100, 250, 100, 650], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [375, 525, 375, 575]]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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 reset is limited by the periodic cap instead of the initial cap.

x = {'initial_bp', 'index_path': index at each reset, 'margin_bp', 'round_to', 'initial_cap_bp', 'periodic_cap_bp', 'lifetime_cap_bp' (above initial), 'floor_bp'}. At each reset the fully indexed rate index + margin is rounded half-up to a multiple of round_to, limited to within the cap of the previous note rate (initial cap at the first reset, periodic afterwards, both directions), then limited to [floor_bp, initial + lifetime cap]. Return the list of note rates.

split: open-access


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

N = 1
observations = []
def solve(x):
    rate = x['initial_bp']
    out = []
    life_max = x['lifetime_cap_bp']
    for i, idx in enumerate(x['index_path']):
        fi = idx + x['margin_bp']
        q, r = divmod(fi, x['round_to'])
        fi = (q + (1 if 2 * r >= x['round_to'] else 0)) * x['round_to']
        cap = x['initial_cap_bp'] if i == 0 else x['periodic_cap_bp']
        new = max(rate - cap, min(fi, rate + cap))
        new = max(x['floor_bp'], min(new, life_max))
        out.append(new)
        rate = new
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: lifetime ceiling base', {'initial_bp': 500, 'index_path': [212, 100, 50, 250, 700], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 400, 400, 500, 600]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [400, 650, 537, 650], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [650, 750, 800, 800]], ['control 1', {'initial_bp': 300, 'index_path': [212, 212], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [475, 475]], ['control 2', {'initial_bp': 300, 'index_path': [100, 50, 250], 'margin_bp': 275, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [400, 350, 550]], ['control 3', {'initial_bp': 300, 'index_path': [650, 212, 100], 'margin_bp': 275, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500, 500, 400]], ['control 4', {'initial_bp': 450, 'index_path': [50, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [300, 325]], ['control 5', {'initial_bp': 500, 'index_path': [212, 212, 250], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 500]]], [['regression: lifetime ceiling base', {'initial_bp': 450, 'index_path': [650, 50, 212], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [650, 550, 500]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [100, 700, 537, 700, 650], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [375, 575, 750, 900, 875]], ['control 1', {'initial_bp': 450, 'index_path': [250, 100, 700], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [475, 325, 525]], ['control 2', {'initial_bp': 500, 'index_path': [212], 'margin_bp': 225, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [375]], ['control 3', {'initial_bp': 450, 'index_path': [50], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [400]], ['control 4', {'initial_bp': 500, 'index_path': [212], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500]], ['control 5', {'initial_bp': 450, 'index_path': [100, 50, 400, 700, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [325, 275, 375, 475, 375]]], [['regression: lifetime ceiling base', {'initial_bp': 450, 'index_path': [212, 650, 50, 650], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [500, 700, 500, 700]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [537, 700, 50], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [800, 800, 600]], ['control 1', {'initial_bp': 450, 'index_path': [250, 250, 212], 'margin_bp': 225, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 450]], ['control 2', {'initial_bp': 450, 'index_path': [100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400]], ['control 3', {'initial_bp': 300, 'index_path': [650], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500]], ['control 4', {'initial_bp': 450, 'index_path': [250, 212, 100, 50, 700], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [475, 425, 400, 400, 500]], ['control 5', {'initial_bp': 300, 'index_path': [212, 50, 100, 50, 400], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [425, 400, 400, 400, 500]]], [['regression: lifetime ceiling base', {'initial_bp': 300, 'index_path': [400, 400, 537], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 675, 800]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [650, 700], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [800, 900]], ['control 1', {'initial_bp': 300, 'index_path': [650, 250, 50, 537, 50], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 375, 575, 375]], ['control 2', {'initial_bp': 300, 'index_path': [250, 250, 250], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [500, 500, 500]], ['control 3', {'initial_bp': 500, 'index_path': [100, 212, 100], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [350, 450, 350]], ['control 4', {'initial_bp': 300, 'index_path': [400, 100, 400, 250, 50], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500, 400, 500, 525, 425]], ['control 5', {'initial_bp': 450, 'index_path': [250, 50, 700], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 400, 500]]], [['regression: lifetime ceiling base', {'initial_bp': 450, 'index_path': [650], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [875]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [537, 50, 650, 537, 650], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [750, 550, 750, 750, 800]], ['control 1', {'initial_bp': 300, 'index_path': [250], 'margin_bp': 225, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [500]], ['control 2', {'initial_bp': 450, 'index_path': [250, 537, 250, 700], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 600, 500, 600]], ['control 3', {'initial_bp': 300, 'index_path': [50, 537, 250, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [300, 400, 475, 375]], ['control 4', {'initial_bp': 300, 'index_path': [50, 50], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400, 400]], ['control 5', {'initial_bp': 450, 'index_path': [100, 250, 100, 650], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [375, 525, 375, 575]]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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):
    rate = x['initial_bp']
    out = []
    life_max = x['initial_bp'] + x['lifetime_cap_bp']
    for i, idx in enumerate(x['index_path']):
        fi = idx + x['margin_bp']
        q, r = divmod(fi, x['round_to'])
        fi = (q + (1 if 2 * r >= x['round_to'] else 0)) * x['round_to']
        cap = x['initial_cap_bp'] if i == 0 else x['periodic_cap_bp']
        new = max(rate - cap, min(fi, rate + cap))
        new = max(x['floor_bp'], min(new, rate + x['lifetime_cap_bp']))
        out.append(new)
        rate = new
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: lifetime ceiling base', {'initial_bp': 500, 'index_path': [212, 100, 50, 250, 700], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 400, 400, 500, 600]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [400, 650, 537, 650], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [650, 750, 800, 800]], ['control 1', {'initial_bp': 300, 'index_path': [212, 212], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [475, 475]], ['control 2', {'initial_bp': 300, 'index_path': [100, 50, 250], 'margin_bp': 275, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [400, 350, 550]], ['control 3', {'initial_bp': 300, 'index_path': [650, 212, 100], 'margin_bp': 275, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500, 500, 400]], ['control 4', {'initial_bp': 450, 'index_path': [50, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [300, 325]], ['control 5', {'initial_bp': 500, 'index_path': [212, 212, 250], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 500]]], [['regression: lifetime ceiling base', {'initial_bp': 450, 'index_path': [650, 50, 212], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [650, 550, 500]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [100, 700, 537, 700, 650], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [375, 575, 750, 900, 875]], ['control 1', {'initial_bp': 450, 'index_path': [250, 100, 700], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [475, 325, 525]], ['control 2', {'initial_bp': 500, 'index_path': [212], 'margin_bp': 225, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [375]], ['control 3', {'initial_bp': 450, 'index_path': [50], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [400]], ['control 4', {'initial_bp': 500, 'index_path': [212], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500]], ['control 5', {'initial_bp': 450, 'index_path': [100, 50, 400, 700, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [325, 275, 375, 475, 375]]], [['regression: lifetime ceiling base', {'initial_bp': 450, 'index_path': [212, 650, 50, 650], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [500, 700, 500, 700]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [537, 700, 50], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [800, 800, 600]], ['control 1', {'initial_bp': 450, 'index_path': [250, 250, 212], 'margin_bp': 225, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 450]], ['control 2', {'initial_bp': 450, 'index_path': [100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400]], ['control 3', {'initial_bp': 300, 'index_path': [650], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500]], ['control 4', {'initial_bp': 450, 'index_path': [250, 212, 100, 50, 700], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [475, 425, 400, 400, 500]], ['control 5', {'initial_bp': 300, 'index_path': [212, 50, 100, 50, 400], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [425, 400, 400, 400, 500]]], [['regression: lifetime ceiling base', {'initial_bp': 300, 'index_path': [400, 400, 537], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 675, 800]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [650, 700], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [800, 900]], ['control 1', {'initial_bp': 300, 'index_path': [650, 250, 50, 537, 50], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 500, 375, 575, 375]], ['control 2', {'initial_bp': 300, 'index_path': [250, 250, 250], 'margin_bp': 250, 'round_to': 50, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [500, 500, 500]], ['control 3', {'initial_bp': 500, 'index_path': [100, 212, 100], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [350, 450, 350]], ['control 4', {'initial_bp': 300, 'index_path': [400, 100, 400, 250, 50], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 400}, [500, 400, 500, 525, 425]], ['control 5', {'initial_bp': 450, 'index_path': [250, 50, 700], 'margin_bp': 250, 'round_to': 25, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [500, 400, 500]]], [['regression: lifetime ceiling base', {'initial_bp': 450, 'index_path': [650], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 300}, [875]], ['regression: lifetime ceiling base, partial-repair probe', {'initial_bp': 300, 'index_path': [537, 50, 650, 537, 650], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 225}, [750, 550, 750, 750, 800]], ['control 1', {'initial_bp': 300, 'index_path': [250], 'margin_bp': 225, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [500]], ['control 2', {'initial_bp': 450, 'index_path': [250, 537, 250, 700], 'margin_bp': 275, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [500, 600, 500, 600]], ['control 3', {'initial_bp': 300, 'index_path': [50, 537, 250, 100], 'margin_bp': 225, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 100, 'lifetime_cap_bp': 600, 'floor_bp': 300}, [300, 400, 475, 375]], ['control 4', {'initial_bp': 300, 'index_path': [50, 50], 'margin_bp': 250, 'round_to': 125, 'initial_cap_bp': 200, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 500, 'floor_bp': 400}, [400, 400]], ['control 5', {'initial_bp': 450, 'index_path': [100, 250, 100, 650], 'margin_bp': 275, 'round_to': 25, 'initial_cap_bp': 500, 'periodic_cap_bp': 200, 'lifetime_cap_bp': 600, 'floor_bp': 225}, [375, 525, 375, 575]]]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'raised ' + type(exc).__name__
    check(label, actual, 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:
Note rates are pinned to the lifetime cap spread itself.

x = {'initial_bp', 'index_path': index at each reset, 'margin_bp', 'round_to', 'initial_cap_bp', 'periodic_cap_bp', 'lifetime_cap_bp' (above initial), 'floor_bp'}. At each reset the fully indexed rate index + margin is rounded half-up to a multiple of round_to, limited to within the cap of the previous note rate (initial cap at the first reset, periodic afterwards, both directions), then limited to [floor_bp, initial + lifetime cap]. Return the list of note rates.

split: open-access