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

N = 1
observations = []
def solve(x):
    avail = x['payment'] + x['suspense']
    applied = {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}
    if avail < x['threshold']:
        return {'applied': applied, 'curtailment': 0, 'refund': 0, 'suspense': x['payment'], 'new_balance': x['balance']}
    for k in ('interest', 'principal', 'late_fee', 'fees'):
        take = min(avail, x['due'][k])
        applied[k] = take
        avail -= take
    room = x['balance'] - applied['principal']
    curt = min(avail, room)
    refund = avail - curt
    return {'applied': applied, 'curtailment': curt, 'refund': refund, 'suspense': 0, 'new_balance': x['balance'] - applied['principal'] - curt}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: held funds amount', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 200, 'threshold': 1000, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 500, 'new_balance': 2000}], ['control 1', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 0, 'threshold': 1250, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 300, 'new_balance': 800}], ['control 2', {'due': {'interest': 1250, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'payment': 7200, 'suspense': 200, 'threshold': 1250, 'balance': 2000}, {'applied': {'interest': 1250, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'curtailment': 1200, 'refund': 4000, 'suspense': 0, 'new_balance': 0}], ['control 3', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'payment': 0, 'suspense': 0, 'threshold': 1000, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 800}], ['control 4', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 1250, 'suspense': 700, 'threshold': 1250, 'balance': 100000}, {'applied': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 700, 'refund': 0, 'suspense': 0, 'new_balance': 99300}], ['control 5', {'due': {'interest': 500, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 0, 'threshold': 1300, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 300, 'new_balance': 800}], ['control 6', {'due': {'interest': 500, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 700, 'threshold': 1000, 'balance': 5000}, {'applied': {'interest': 500, 'principal': 500, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 4500}]], [['regression: held funds amount', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 150, 'fees': 0}, 'payment': 0, 'suspense': 700, 'threshold': 1250, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 700, 'new_balance': 800}], ['regression: held funds amount, partial-repair probe', {'due': {'interest': 500, 'principal': 0, 'late_fee': 150, 'fees': 0}, 'payment': 649, 'suspense': 0, 'threshold': 650, 'balance': 100000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 649, 'new_balance': 100000}], ['control 1', {'due': {'interest': 500, 'principal': 2000, 'late_fee': 0, 'fees': 35}, 'payment': 300, 'suspense': 700, 'threshold': 1000, 'balance': 2000}, {'applied': {'interest': 500, 'principal': 500, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 1500}], ['control 2', {'due': {'interest': 500, 'principal': 2000, 'late_fee': 0, 'fees': 35}, 'payment': 2500, 'suspense': 200, 'threshold': 0, 'balance': 5000}, {'applied': {'interest': 500, 'principal': 2000, 'late_fee': 0, 'fees': 35}, 'curtailment': 165, 'refund': 0, 'suspense': 0, 'new_balance': 2835}], ['control 3', {'due': {'interest': 0, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'payment': 2500, 'suspense': 0, 'threshold': 950, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'curtailment': 1200, 'refund': 350, 'suspense': 0, 'new_balance': 0}], ['control 4', {'due': {'interest': 1250, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'payment': 2201, 'suspense': 200, 'threshold': 1250, 'balance': 5000}, {'applied': {'interest': 1250, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'curtailment': 201, 'refund': 0, 'suspense': 0, 'new_balance': 3999}], ['control 5', {'due': {'interest': 0, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'payment': 2500, 'suspense': 0, 'threshold': 0, 'balance': 800}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'curtailment': 0, 'refund': 1550, 'suspense': 0, 'new_balance': 0}]], [['regression: held funds amount', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 0, 'suspense': 200, 'threshold': 1000, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 200, 'new_balance': 800}], ['regression: held funds amount, partial-repair probe', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 200, 'threshold': 1250, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 500, 'new_balance': 2000}], ['control 1', {'due': {'interest': 0, 'principal': 2000, 'late_fee': 150, 'fees': 0}, 'payment': 300, 'suspense': 700, 'threshold': 0, 'balance': 800}, {'applied': {'interest': 0, 'principal': 1000, 'late_fee': 0, 'fees': 0}, 'curtailment': -200, 'refund': 200, 'suspense': 0, 'new_balance': 0}], ['control 2', {'due': {'interest': 0, 'principal': 2000, 'late_fee': 0, 'fees': 0}, 'payment': 1000, 'suspense': 0, 'threshold': 1000, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 1000, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 4000}], ['control 3', {'due': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 35}, 'payment': 835, 'suspense': 0, 'threshold': 835, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 35}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 4200}], ['control 4', {'due': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 5800, 'suspense': 0, 'threshold': 800, 'balance': 100000}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'curtailment': 5000, 'refund': 0, 'suspense': 0, 'new_balance': 94200}], ['control 5', {'due': {'interest': 500, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 499, 'suspense': 200, 'threshold': 500, 'balance': 2000}, {'applied': {'interest': 500, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 199, 'refund': 0, 'suspense': 0, 'new_balance': 1801}]], [['regression: held funds amount', {'due': {'interest': 0, 'principal': 2000, 'late_fee': 0, 'fees': 35}, 'payment': 1000, 'suspense': 700, 'threshold': 2035, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 1700, 'new_balance': 2000}], ['control 1', {'due': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'payment': 36, 'suspense': 700, 'threshold': 35, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'curtailment': 701, 'refund': 0, 'suspense': 0, 'new_balance': 99}], ['control 2', {'due': {'interest': 0, 'principal': 2000, 'late_fee': 150, 'fees': 0}, 'payment': 1000, 'suspense': 700, 'threshold': 1000, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 1700, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 3300}], ['control 3', {'due': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 5800, 'suspense': 200, 'threshold': 1000, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'curtailment': 4200, 'refund': 1000, 'suspense': 0, 'new_balance': 0}], ['control 4', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 150, 'fees': 0}, 'payment': 1000, 'suspense': 0, 'threshold': 1000, 'balance': 2000}, {'applied': {'interest': 1000, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 2000}], ['control 5', {'due': {'interest': 1250, 'principal': 2000, 'late_fee': 0, 'fees': 0}, 'payment': 8250, 'suspense': 200, 'threshold': 3250, 'balance': 800}, {'applied': {'interest': 1250, 'principal': 2000, 'late_fee': 0, 'fees': 0}, 'curtailment': -1200, 'refund': 6400, 'suspense': 0, 'new_balance': 0}], ['control 6', {'due': {'interest': 500, 'principal': 2000, 'late_fee': 0, 'fees': 0}, 'payment': 1000, 'suspense': 200, 'threshold': 1000, 'balance': 800}, {'applied': {'interest': 500, 'principal': 700, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 100}]], [['regression: held funds amount', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 0, 'suspense': 700, 'threshold': 1250, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 700, 'new_balance': 5000}], ['regression: held funds amount, partial-repair probe', {'due': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 35}, 'payment': 834, 'suspense': 0, 'threshold': 835, 'balance': 100000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 834, 'new_balance': 100000}], ['control 1', {'due': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': -1, 'suspense': 200, 'threshold': 0, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 199, 'refund': 0, 'suspense': 0, 'new_balance': 1801}], ['control 2', {'due': {'interest': 500, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 1300, 'suspense': 0, 'threshold': 1000, 'balance': 800}, {'applied': {'interest': 500, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 0}], ['control 3', {'due': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'payment': 300, 'suspense': 700, 'threshold': 0, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'curtailment': 800, 'refund': 165, 'suspense': 0, 'new_balance': 0}], ['control 4', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 150, 'fees': 0}, 'payment': 300, 'suspense': 0, 'threshold': 0, 'balance': 100000}, {'applied': {'interest': 300, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 100000}], ['control 5', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 1000, 'suspense': 0, 'threshold': 1000, 'balance': 2000}, {'applied': {'interest': 1000, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 2000}]]]
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):
    avail = x['payment'] + x['suspense']
    applied = {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}
    if avail < x['threshold']:
        return {'applied': applied, 'curtailment': 0, 'refund': 0, 'suspense': x['suspense'], 'new_balance': x['balance']}
    for k in ('interest', 'principal', 'late_fee', 'fees'):
        take = min(avail, x['due'][k])
        applied[k] = take
        avail -= take
    room = x['balance'] - applied['principal']
    curt = min(avail, room)
    refund = avail - curt
    return {'applied': applied, 'curtailment': curt, 'refund': refund, 'suspense': 0, 'new_balance': x['balance'] - applied['principal'] - curt}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: held funds amount', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 200, 'threshold': 1000, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 500, 'new_balance': 2000}], ['control 1', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 0, 'threshold': 1250, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 300, 'new_balance': 800}], ['control 2', {'due': {'interest': 1250, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'payment': 7200, 'suspense': 200, 'threshold': 1250, 'balance': 2000}, {'applied': {'interest': 1250, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'curtailment': 1200, 'refund': 4000, 'suspense': 0, 'new_balance': 0}], ['control 3', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'payment': 0, 'suspense': 0, 'threshold': 1000, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 800}], ['control 4', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 1250, 'suspense': 700, 'threshold': 1250, 'balance': 100000}, {'applied': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 700, 'refund': 0, 'suspense': 0, 'new_balance': 99300}], ['control 5', {'due': {'interest': 500, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 0, 'threshold': 1300, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 300, 'new_balance': 800}], ['control 6', {'due': {'interest': 500, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 700, 'threshold': 1000, 'balance': 5000}, {'applied': {'interest': 500, 'principal': 500, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 4500}]], [['regression: held funds amount', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 150, 'fees': 0}, 'payment': 0, 'suspense': 700, 'threshold': 1250, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 700, 'new_balance': 800}], ['regression: held funds amount, partial-repair probe', {'due': {'interest': 500, 'principal': 0, 'late_fee': 150, 'fees': 0}, 'payment': 649, 'suspense': 0, 'threshold': 650, 'balance': 100000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 649, 'new_balance': 100000}], ['control 1', {'due': {'interest': 500, 'principal': 2000, 'late_fee': 0, 'fees': 35}, 'payment': 300, 'suspense': 700, 'threshold': 1000, 'balance': 2000}, {'applied': {'interest': 500, 'principal': 500, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 1500}], ['control 2', {'due': {'interest': 500, 'principal': 2000, 'late_fee': 0, 'fees': 35}, 'payment': 2500, 'suspense': 200, 'threshold': 0, 'balance': 5000}, {'applied': {'interest': 500, 'principal': 2000, 'late_fee': 0, 'fees': 35}, 'curtailment': 165, 'refund': 0, 'suspense': 0, 'new_balance': 2835}], ['control 3', {'due': {'interest': 0, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'payment': 2500, 'suspense': 0, 'threshold': 950, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'curtailment': 1200, 'refund': 350, 'suspense': 0, 'new_balance': 0}], ['control 4', {'due': {'interest': 1250, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'payment': 2201, 'suspense': 200, 'threshold': 1250, 'balance': 5000}, {'applied': {'interest': 1250, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'curtailment': 201, 'refund': 0, 'suspense': 0, 'new_balance': 3999}], ['control 5', {'due': {'interest': 0, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'payment': 2500, 'suspense': 0, 'threshold': 0, 'balance': 800}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 150, 'fees': 0}, 'curtailment': 0, 'refund': 1550, 'suspense': 0, 'new_balance': 0}]], [['regression: held funds amount', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 0, 'suspense': 200, 'threshold': 1000, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 200, 'new_balance': 800}], ['regression: held funds amount, partial-repair probe', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 300, 'suspense': 200, 'threshold': 1250, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 500, 'new_balance': 2000}], ['control 1', {'due': {'interest': 0, 'principal': 2000, 'late_fee': 150, 'fees': 0}, 'payment': 300, 'suspense': 700, 'threshold': 0, 'balance': 800}, {'applied': {'interest': 0, 'principal': 1000, 'late_fee': 0, 'fees': 0}, 'curtailment': -200, 'refund': 200, 'suspense': 0, 'new_balance': 0}], ['control 2', {'due': {'interest': 0, 'principal': 2000, 'late_fee': 0, 'fees': 0}, 'payment': 1000, 'suspense': 0, 'threshold': 1000, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 1000, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 4000}], ['control 3', {'due': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 35}, 'payment': 835, 'suspense': 0, 'threshold': 835, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 35}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 4200}], ['control 4', {'due': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 5800, 'suspense': 0, 'threshold': 800, 'balance': 100000}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'curtailment': 5000, 'refund': 0, 'suspense': 0, 'new_balance': 94200}], ['control 5', {'due': {'interest': 500, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 499, 'suspense': 200, 'threshold': 500, 'balance': 2000}, {'applied': {'interest': 500, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 199, 'refund': 0, 'suspense': 0, 'new_balance': 1801}]], [['regression: held funds amount', {'due': {'interest': 0, 'principal': 2000, 'late_fee': 0, 'fees': 35}, 'payment': 1000, 'suspense': 700, 'threshold': 2035, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 1700, 'new_balance': 2000}], ['control 1', {'due': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'payment': 36, 'suspense': 700, 'threshold': 35, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'curtailment': 701, 'refund': 0, 'suspense': 0, 'new_balance': 99}], ['control 2', {'due': {'interest': 0, 'principal': 2000, 'late_fee': 150, 'fees': 0}, 'payment': 1000, 'suspense': 700, 'threshold': 1000, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 1700, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 3300}], ['control 3', {'due': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 5800, 'suspense': 200, 'threshold': 1000, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'curtailment': 4200, 'refund': 1000, 'suspense': 0, 'new_balance': 0}], ['control 4', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 150, 'fees': 0}, 'payment': 1000, 'suspense': 0, 'threshold': 1000, 'balance': 2000}, {'applied': {'interest': 1000, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 2000}], ['control 5', {'due': {'interest': 1250, 'principal': 2000, 'late_fee': 0, 'fees': 0}, 'payment': 8250, 'suspense': 200, 'threshold': 3250, 'balance': 800}, {'applied': {'interest': 1250, 'principal': 2000, 'late_fee': 0, 'fees': 0}, 'curtailment': -1200, 'refund': 6400, 'suspense': 0, 'new_balance': 0}], ['control 6', {'due': {'interest': 500, 'principal': 2000, 'late_fee': 0, 'fees': 0}, 'payment': 1000, 'suspense': 200, 'threshold': 1000, 'balance': 800}, {'applied': {'interest': 500, 'principal': 700, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 100}]], [['regression: held funds amount', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 0, 'suspense': 700, 'threshold': 1250, 'balance': 5000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 700, 'new_balance': 5000}], ['regression: held funds amount, partial-repair probe', {'due': {'interest': 0, 'principal': 800, 'late_fee': 0, 'fees': 35}, 'payment': 834, 'suspense': 0, 'threshold': 835, 'balance': 100000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 834, 'new_balance': 100000}], ['control 1', {'due': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': -1, 'suspense': 200, 'threshold': 0, 'balance': 2000}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 199, 'refund': 0, 'suspense': 0, 'new_balance': 1801}], ['control 2', {'due': {'interest': 500, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'payment': 1300, 'suspense': 0, 'threshold': 1000, 'balance': 800}, {'applied': {'interest': 500, 'principal': 800, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 0}], ['control 3', {'due': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'payment': 300, 'suspense': 700, 'threshold': 0, 'balance': 800}, {'applied': {'interest': 0, 'principal': 0, 'late_fee': 0, 'fees': 35}, 'curtailment': 800, 'refund': 165, 'suspense': 0, 'new_balance': 0}], ['control 4', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 150, 'fees': 0}, 'payment': 300, 'suspense': 0, 'threshold': 0, 'balance': 100000}, {'applied': {'interest': 300, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 100000}], ['control 5', {'due': {'interest': 1250, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'payment': 1000, 'suspense': 0, 'threshold': 1000, 'balance': 2000}, {'applied': {'interest': 1000, 'principal': 0, 'late_fee': 0, 'fees': 0}, 'curtailment': 0, 'refund': 0, 'suspense': 0, 'new_balance': 2000}]]]
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:
Suspense loses its prior balance when another short payment arrives.

x = {'due': {'interest', 'principal', 'late_fee', 'fees'}, 'payment', 'suspense', 'threshold', 'balance'}. Available = payment + suspense. If available < threshold, everything goes to suspense and nothing is applied. Otherwise apply in order interest, principal, late_fee, fees, then curtail principal with the remainder up to balance - applied principal; the rest is refunded. Return {'applied', 'curtailment', 'refund', 'suspense', 'new_balance'}.

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(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: grace deadline inclusivity', {'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 1', {'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 2', {'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 3', {'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 4', {'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 5', {'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 6', {'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}]], [['regression: grace deadline inclusivity', {'due_day': 15, 'grace': 10, 'paid_day': 25, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['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': 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 5', {'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 6', {'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}]], [['regression: grace deadline inclusivity', {'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}], ['regression: grace deadline inclusivity, partial-repair probe', {'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 1', {'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 2', {'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 3', {'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 4', {'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 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: grace deadline inclusivity', {'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: grace deadline inclusivity, partial-repair probe', {'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 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': 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 4', {'due_day': 15, 'grace': 15, 'paid_day': 31, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 35}, {'late': True, 'fee': 1000, 'days_late': 16}], ['control 5', {'due_day': 15, 'grace': 10, 'paid_day': 26, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 5000, 'days_late': 11}]], [['regression: grace deadline inclusivity', {'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}], ['regression: grace deadline inclusivity, partial-repair probe', {'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 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': 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 3', {'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 4', {'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 5', {'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}]]]
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 or x['grace'] == 0) 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'], 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: grace deadline inclusivity', {'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 1', {'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 2', {'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 3', {'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 4', {'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 5', {'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 6', {'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}]], [['regression: grace deadline inclusivity', {'due_day': 15, 'grace': 10, 'paid_day': 25, 'payment_due': 2500, 'paid_amount': 20000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 10000, 'as_of': 35}, {'late': False, 'fee': 0, 'days_late': 0}], ['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': 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 5', {'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 6', {'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}]], [['regression: grace deadline inclusivity', {'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}], ['regression: grace deadline inclusivity, partial-repair probe', {'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 1', {'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 2', {'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 3', {'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 4', {'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 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: grace deadline inclusivity', {'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: grace deadline inclusivity, partial-repair probe', {'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 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': 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 4', {'due_day': 15, 'grace': 15, 'paid_day': 31, 'payment_due': 20000, 'paid_amount': 20000, 'tolerance': 10, 'fee_bp': 500, 'fee_min': 0, 'fee_max': 10000, 'as_of': 35}, {'late': True, 'fee': 1000, 'days_late': 16}], ['control 5', {'due_day': 15, 'grace': 10, 'paid_day': 26, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 100, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 55}, {'late': True, 'fee': 5000, 'days_late': 11}]], [['regression: grace deadline inclusivity', {'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}], ['regression: grace deadline inclusivity, partial-repair probe', {'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 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': 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 3', {'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 4', {'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 5', {'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}]]]
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:
A payment received on the last grace day is charged a late 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):
    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 <= 0
    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'], 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: shortfall tolerance', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 150000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 1', {'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 2', {'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 3', {'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 4', {'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 5', {'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 6', {'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}]], [['regression: shortfall tolerance', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 100000, '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: shortfall tolerance, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['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': 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 5', {'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}]], [['regression: shortfall tolerance', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['regression: shortfall tolerance, partial-repair probe', {'due_day': 1, 'grace': 0, 'paid_day': 0, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['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': 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 4', {'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 5', {'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: shortfall tolerance', {'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}], ['regression: shortfall tolerance, partial-repair probe', {'due_day': 5, 'grace': 10, 'paid_day': 15, 'payment_due': 2500, 'paid_amount': 2500, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['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: shortfall tolerance', {'due_day': 1, 'grace': 15, 'paid_day': 0, 'payment_due': 150000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, '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': 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 6', {'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'], 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: shortfall tolerance', {'due_day': 5, 'grace': 0, 'paid_day': 4, 'payment_due': 150000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['control 1', {'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 2', {'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 3', {'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 4', {'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 5', {'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 6', {'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}]], [['regression: shortfall tolerance', {'due_day': 1, 'grace': 0, 'paid_day': 1, 'payment_due': 100000, '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: shortfall tolerance, partial-repair probe', {'due_day': 5, 'grace': 0, 'paid_day': 5, 'payment_due': 100000, 'paid_amount': 100000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 45}, {'late': False, 'fee': 0, 'days_late': 0}], ['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': 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 5', {'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}]], [['regression: shortfall tolerance', {'due_day': 1, 'grace': 15, 'paid_day': 16, 'payment_due': 100000, 'paid_amount': 99999, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['regression: shortfall tolerance, partial-repair probe', {'due_day': 1, 'grace': 0, 'paid_day': 0, 'payment_due': 150000, 'paid_amount': 150000, 'tolerance': 0, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 10000, 'as_of': 41}, {'late': False, 'fee': 0, 'days_late': 0}], ['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': 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 4', {'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 5', {'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: shortfall tolerance', {'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}], ['regression: shortfall tolerance, partial-repair probe', {'due_day': 5, 'grace': 10, 'paid_day': 15, 'payment_due': 2500, 'paid_amount': 2500, 'tolerance': 0, 'fee_bp': 500, 'fee_min': 2500, 'fee_max': 5000, 'as_of': 25}, {'late': False, 'fee': 0, 'days_late': 0}], ['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: shortfall tolerance', {'due_day': 1, 'grace': 15, 'paid_day': 0, 'payment_due': 150000, 'paid_amount': 149990, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 0, 'fee_max': 5000, 'as_of': 21}, {'late': False, 'fee': 0, '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': 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 6', {'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:
Payments a few cents short are treated as late.

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(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 - deadline)}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: days late origin', {'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 1', {'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 2', {'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 3', {'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 4', {'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 5', {'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 6', {'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}]], [['regression: days late origin', {'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 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': 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 5', {'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 6', {'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}]], [['regression: days late origin', {'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': 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 4', {'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 5', {'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 6', {'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: days late origin', {'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 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': 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 3', {'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 4', {'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 5', {'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 6', {'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}]], [['regression: days late origin', {'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': 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 2', {'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 3', {'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 4', {'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 5', {'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 6', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 100000, 'paid_amount': 2500, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 21}, {'late': True, 'fee': 4000, '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'], min(fee, x['fee_max']))
    return {'late': True, 'fee': fee, 'days_late': max(0, end - x['due_day'] + 1)}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: days late origin', {'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 1', {'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 2', {'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 3', {'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 4', {'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 5', {'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 6', {'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}]], [['regression: days late origin', {'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 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': 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 5', {'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 6', {'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}]], [['regression: days late origin', {'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': 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 4', {'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 5', {'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 6', {'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: days late origin', {'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 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': 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 3', {'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 4', {'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 5', {'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 6', {'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}]], [['regression: days late origin', {'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': 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 2', {'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 3', {'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 4', {'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 5', {'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 6', {'due_day': 1, 'grace': 10, 'paid_day': 1, 'payment_due': 100000, 'paid_amount': 2500, 'tolerance': 10, 'fee_bp': 400, 'fee_min': 1500, 'fee_max': 10000, 'as_of': 21}, {'late': True, 'fee': 4000, '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:
Days late are understated by the grace period.

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