FA-58621 / Loan amortization schedules / Open access
Rule of 78s early payoff rebate: total digits denominator · case 01
Rebates are overstated for every payoff.
ROOT CAUSE
The denominator uses n squared.
VERIFIED REPAIR
Divide by n(n+1).
Unsuccessful approach: Halving the denominator without halving the numerator doubles the rebate.
Case contract
x = {'term' n, 'paid' k, 'finance_charge', 'acq_fee' (fully earned up front), 'payment', 'min_rebate'}. Rebatable charge = finance_charge - acq_fee; remaining r = n - k; rebate = round_half_up(rebatable * r(r+1) / (n(n+1))), set to 0 when below min_rebate. Payoff = payment*r - rebate; earned = finance_charge - rebate. Return {'rebate', 'payoff', 'earned'}.
Why this case matters
Amortization engines drive borrower statements, payoff quotes and investor remittances; a misplaced rounding step, boundary or ordering rule compounds across hundreds of periods.
1 / The failure
Exit 1"""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)
n = x['term']
k = x['paid']
fc = x['finance_charge'] - x['acq_fee']
rem = n - k
rebate = rnd(fc * rem * (rem + 1), n * n)
if rebate < x['min_rebate']:
rebate = 0
remaining = x['payment'] * rem
return {'rebate': rebate, 'payoff': remaining - rebate, 'earned': x['finance_charge'] - rebate}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: total digits denominator', {'term': 36, 'paid': 35, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 180, 'payoff': 9820, 'earned': 119820}], ['control 1', {'term': 36, 'paid': 35, 'finance_charge': 50000, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 25000, 'earned': 50000}], ['control 2', {'term': 24, 'paid': 23, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 25000, 'earned': 100}], ['control 3', {'term': 12, 'paid': 3, 'finance_charge': 100, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 100}, {'rebate': 0, 'payoff': 38889, 'earned': 100}], ['control 4', {'term': 6, 'paid': 0, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 60000, 'earned': 100}], ['control 5', {'term': 24, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 51852, 'earned': 7777}], ['control 6', {'term': 6, 'paid': 6, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 7777}]], [['regression: total digits denominator', {'term': 36, 'paid': 3, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 500}, {'rebate': 4445, 'payoff': 325555, 'earned': 3332}], ['control 1', {'term': 12, 'paid': 1, 'finance_charge': 100, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 110000, 'earned': 100}], ['control 2', {'term': 24, 'paid': 24, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 0, 'earned': 120000}], ['control 3', {'term': 36, 'paid': 0, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 900000, 'earned': 100}], ['control 4', {'term': 24, 'paid': 12, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 120000, 'earned': 100}], ['control 5', {'term': 24, 'paid': 23, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 4321, 'earned': 120000}], ['control 6', {'term': 36, 'paid': 35, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 4321, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 4321, 'earned': 7777}]], [['regression: total digits denominator', {'term': 24, 'paid': 3, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 92400, 'payoff': 117600, 'earned': 27600}], ['control 1', {'term': 6, 'paid': 5, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 25000, 'earned': 100}], ['control 2', {'term': 12, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 3', {'term': 12, 'paid': 1, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 25000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 275000, 'earned': 100}], ['control 4', {'term': 24, 'paid': 24, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 5', {'term': 36, 'paid': 18, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 77778, 'earned': 100}], ['control 6', {'term': 12, 'paid': 12, 'finance_charge': 100, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 100}]], [['regression: total digits denominator', {'term': 12, 'paid': 0, 'finance_charge': 7777, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 2000}, {'rebate': 7777, 'payoff': 44075, 'earned': 0}], ['control 1', {'term': 36, 'paid': 0, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 900000, 'earned': 100}], ['control 2', {'term': 12, 'paid': 12, 'finance_charge': 50000, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 50000}], ['control 3', {'term': 6, 'paid': 3, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 75000, 'earned': 100}], ['control 4', {'term': 36, 'paid': 18, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 0}, {'rebate': 26, 'payoff': 449974, 'earned': 74}], ['control 5', {'term': 12, 'paid': 12, 'finance_charge': 50000, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 50000}], ['control 6', {'term': 24, 'paid': 1, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 0}, {'rebate': 0, 'payoff': 99383, 'earned': 100}]], [['regression: total digits denominator', {'term': 24, 'paid': 12, 'finance_charge': 120000, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 29250, 'payoff': 270750, 'earned': 90750}], ['control 1', {'term': 24, 'paid': 12, 'finance_charge': 100, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 51852, 'earned': 100}], ['control 2', {'term': 36, 'paid': 0, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 900000, 'earned': 7777}], ['control 3', {'term': 36, 'paid': 36, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 100}], ['control 4', {'term': 12, 'paid': 0, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 300000, 'earned': 100}], ['control 5', {'term': 12, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 6', {'term': 6, 'paid': 5, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 100}, {'rebate': 0, 'payoff': 4321, 'earned': 100}]]]
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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: total digits denominator | {'earned': 119815, 'payoff': 9815, 'rebate': 185} | {'earned': 119820, 'payoff': 9820, 'rebate': 180} | Failed |
| control 1 | {'earned': 50000, 'payoff': 25000, 'rebate': 0} | {'earned': 50000, 'payoff': 25000, 'rebate': 0} | Passed |
| control 2 | {'earned': 100, 'payoff': 25000, 'rebate': 0} | {'earned': 100, 'payoff': 25000, 'rebate': 0} | Passed |
| control 3 | {'earned': 100, 'payoff': 38889, 'rebate': 0} | {'earned': 100, 'payoff': 38889, 'rebate': 0} | Passed |
| control 4 | {'earned': 100, 'payoff': 60000, 'rebate': 0} | {'earned': 100, 'payoff': 60000, 'rebate': 0} | Passed |
| control 5 | {'earned': 7777, 'payoff': 51852, 'rebate': 0} | {'earned': 7777, 'payoff': 51852, 'rebate': 0} | Passed |
| control 6 | {'earned': 7777, 'payoff': 0, 'rebate': 0} | {'earned': 7777, 'payoff': 0, 'rebate': 0} | Passed |
SHA-256 / d86d52bc6e11e99267f7cd645872a1ac97887874a4d228e664316c8581b32615
2 / The unsuccessful fix
Exit 1"""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)
n = x['term']
k = x['paid']
fc = x['finance_charge'] - x['acq_fee']
rem = n - k
rebate = rnd(fc * rem * (rem + 1), n * (n + 1) // 2)
if rebate < x['min_rebate']:
rebate = 0
remaining = x['payment'] * rem
return {'rebate': rebate, 'payoff': remaining - rebate, 'earned': x['finance_charge'] - rebate}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: total digits denominator', {'term': 36, 'paid': 35, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 180, 'payoff': 9820, 'earned': 119820}], ['control 1', {'term': 36, 'paid': 35, 'finance_charge': 50000, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 25000, 'earned': 50000}], ['control 2', {'term': 24, 'paid': 23, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 25000, 'earned': 100}], ['control 3', {'term': 12, 'paid': 3, 'finance_charge': 100, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 100}, {'rebate': 0, 'payoff': 38889, 'earned': 100}], ['control 4', {'term': 6, 'paid': 0, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 60000, 'earned': 100}], ['control 5', {'term': 24, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 51852, 'earned': 7777}], ['control 6', {'term': 6, 'paid': 6, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 7777}]], [['regression: total digits denominator', {'term': 36, 'paid': 3, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 500}, {'rebate': 4445, 'payoff': 325555, 'earned': 3332}], ['control 1', {'term': 12, 'paid': 1, 'finance_charge': 100, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 110000, 'earned': 100}], ['control 2', {'term': 24, 'paid': 24, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 0, 'earned': 120000}], ['control 3', {'term': 36, 'paid': 0, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 900000, 'earned': 100}], ['control 4', {'term': 24, 'paid': 12, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 120000, 'earned': 100}], ['control 5', {'term': 24, 'paid': 23, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 4321, 'earned': 120000}], ['control 6', {'term': 36, 'paid': 35, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 4321, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 4321, 'earned': 7777}]], [['regression: total digits denominator', {'term': 24, 'paid': 3, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 92400, 'payoff': 117600, 'earned': 27600}], ['control 1', {'term': 6, 'paid': 5, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 25000, 'earned': 100}], ['control 2', {'term': 12, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 3', {'term': 12, 'paid': 1, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 25000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 275000, 'earned': 100}], ['control 4', {'term': 24, 'paid': 24, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 5', {'term': 36, 'paid': 18, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 77778, 'earned': 100}], ['control 6', {'term': 12, 'paid': 12, 'finance_charge': 100, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 100}]], [['regression: total digits denominator', {'term': 12, 'paid': 0, 'finance_charge': 7777, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 2000}, {'rebate': 7777, 'payoff': 44075, 'earned': 0}], ['control 1', {'term': 36, 'paid': 0, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 900000, 'earned': 100}], ['control 2', {'term': 12, 'paid': 12, 'finance_charge': 50000, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 50000}], ['control 3', {'term': 6, 'paid': 3, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 75000, 'earned': 100}], ['control 4', {'term': 36, 'paid': 18, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 0}, {'rebate': 26, 'payoff': 449974, 'earned': 74}], ['control 5', {'term': 12, 'paid': 12, 'finance_charge': 50000, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 50000}], ['control 6', {'term': 24, 'paid': 1, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 0}, {'rebate': 0, 'payoff': 99383, 'earned': 100}]], [['regression: total digits denominator', {'term': 24, 'paid': 12, 'finance_charge': 120000, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 29250, 'payoff': 270750, 'earned': 90750}], ['control 1', {'term': 24, 'paid': 12, 'finance_charge': 100, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 51852, 'earned': 100}], ['control 2', {'term': 36, 'paid': 0, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 900000, 'earned': 7777}], ['control 3', {'term': 36, 'paid': 36, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 100}], ['control 4', {'term': 12, 'paid': 0, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 300000, 'earned': 100}], ['control 5', {'term': 12, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 6', {'term': 6, 'paid': 5, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 100}, {'rebate': 0, 'payoff': 4321, 'earned': 100}]]]
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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: total digits denominator | {'earned': 119640, 'payoff': 9640, 'rebate': 360} | {'earned': 119820, 'payoff': 9820, 'rebate': 180} | Failed |
| control 1 | {'earned': 49872, 'payoff': 24872, 'rebate': 128} | {'earned': 50000, 'payoff': 25000, 'rebate': 0} | Failed |
| control 2 | {'earned': 100, 'payoff': 25000, 'rebate': 0} | {'earned': 100, 'payoff': 25000, 'rebate': 0} | Passed |
| control 3 | {'earned': -15, 'payoff': 38774, 'rebate': 115} | {'earned': 100, 'payoff': 38889, 'rebate': 0} | Failed |
| control 4 | {'earned': 100, 'payoff': 60000, 'rebate': 0} | {'earned': 100, 'payoff': 60000, 'rebate': 0} | Passed |
| control 5 | {'earned': 7777, 'payoff': 51852, 'rebate': 0} | {'earned': 7777, 'payoff': 51852, 'rebate': 0} | Passed |
| control 6 | {'earned': 7777, 'payoff': 0, 'rebate': 0} | {'earned': 7777, 'payoff': 0, 'rebate': 0} | Passed |
SHA-256 / 8a68eb3ca942dea416bd743dbb59884870d502cbadff9fe39cfb3d1e2830a184
3 / The verified repair
Exit 0"""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)
n = x['term']
k = x['paid']
fc = x['finance_charge'] - x['acq_fee']
rem = n - k
rebate = rnd(fc * rem * (rem + 1), n * (n + 1))
if rebate < x['min_rebate']:
rebate = 0
remaining = x['payment'] * rem
return {'rebate': rebate, 'payoff': remaining - rebate, 'earned': x['finance_charge'] - rebate}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: total digits denominator', {'term': 36, 'paid': 35, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 180, 'payoff': 9820, 'earned': 119820}], ['control 1', {'term': 36, 'paid': 35, 'finance_charge': 50000, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 25000, 'earned': 50000}], ['control 2', {'term': 24, 'paid': 23, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 25000, 'earned': 100}], ['control 3', {'term': 12, 'paid': 3, 'finance_charge': 100, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 100}, {'rebate': 0, 'payoff': 38889, 'earned': 100}], ['control 4', {'term': 6, 'paid': 0, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 60000, 'earned': 100}], ['control 5', {'term': 24, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 51852, 'earned': 7777}], ['control 6', {'term': 6, 'paid': 6, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 7777}]], [['regression: total digits denominator', {'term': 36, 'paid': 3, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 500}, {'rebate': 4445, 'payoff': 325555, 'earned': 3332}], ['control 1', {'term': 12, 'paid': 1, 'finance_charge': 100, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 110000, 'earned': 100}], ['control 2', {'term': 24, 'paid': 24, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 100}, {'rebate': 0, 'payoff': 0, 'earned': 120000}], ['control 3', {'term': 36, 'paid': 0, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 900000, 'earned': 100}], ['control 4', {'term': 24, 'paid': 12, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 120000, 'earned': 100}], ['control 5', {'term': 24, 'paid': 23, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 4321, 'earned': 120000}], ['control 6', {'term': 36, 'paid': 35, 'finance_charge': 7777, 'acq_fee': 2500, 'payment': 4321, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 4321, 'earned': 7777}]], [['regression: total digits denominator', {'term': 24, 'paid': 3, 'finance_charge': 120000, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 92400, 'payoff': 117600, 'earned': 27600}], ['control 1', {'term': 6, 'paid': 5, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 25000, 'earned': 100}], ['control 2', {'term': 12, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 3', {'term': 12, 'paid': 1, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 25000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 275000, 'earned': 100}], ['control 4', {'term': 24, 'paid': 24, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 5', {'term': 36, 'paid': 18, 'finance_charge': 100, 'acq_fee': 2500, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 77778, 'earned': 100}], ['control 6', {'term': 12, 'paid': 12, 'finance_charge': 100, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 100}]], [['regression: total digits denominator', {'term': 12, 'paid': 0, 'finance_charge': 7777, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 2000}, {'rebate': 7777, 'payoff': 44075, 'earned': 0}], ['control 1', {'term': 36, 'paid': 0, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 900000, 'earned': 100}], ['control 2', {'term': 12, 'paid': 12, 'finance_charge': 50000, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 50000}], ['control 3', {'term': 6, 'paid': 3, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 75000, 'earned': 100}], ['control 4', {'term': 36, 'paid': 18, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 0}, {'rebate': 26, 'payoff': 449974, 'earned': 74}], ['control 5', {'term': 12, 'paid': 12, 'finance_charge': 50000, 'acq_fee': 2500, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 50000}], ['control 6', {'term': 24, 'paid': 1, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 0}, {'rebate': 0, 'payoff': 99383, 'earned': 100}]], [['regression: total digits denominator', {'term': 24, 'paid': 12, 'finance_charge': 120000, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 500}, {'rebate': 29250, 'payoff': 270750, 'earned': 90750}], ['control 1', {'term': 24, 'paid': 12, 'finance_charge': 100, 'acq_fee': 0, 'payment': 4321, 'min_rebate': 500}, {'rebate': 0, 'payoff': 51852, 'earned': 100}], ['control 2', {'term': 36, 'paid': 0, 'finance_charge': 7777, 'acq_fee': 7500, 'payment': 25000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 900000, 'earned': 7777}], ['control 3', {'term': 36, 'paid': 36, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 0}, {'rebate': 0, 'payoff': 0, 'earned': 100}], ['control 4', {'term': 12, 'paid': 0, 'finance_charge': 100, 'acq_fee': 0, 'payment': 25000, 'min_rebate': 500}, {'rebate': 0, 'payoff': 300000, 'earned': 100}], ['control 5', {'term': 12, 'paid': 12, 'finance_charge': 7777, 'acq_fee': 0, 'payment': 10000, 'min_rebate': 2000}, {'rebate': 0, 'payoff': 0, 'earned': 7777}], ['control 6', {'term': 6, 'paid': 5, 'finance_charge': 100, 'acq_fee': 7500, 'payment': 4321, 'min_rebate': 100}, {'rebate': 0, 'payoff': 4321, 'earned': 100}]]]
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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: total digits denominator | {'earned': 119820, 'payoff': 9820, 'rebate': 180} | {'earned': 119820, 'payoff': 9820, 'rebate': 180} | Passed |
| control 1 | {'earned': 50000, 'payoff': 25000, 'rebate': 0} | {'earned': 50000, 'payoff': 25000, 'rebate': 0} | Passed |
| control 2 | {'earned': 100, 'payoff': 25000, 'rebate': 0} | {'earned': 100, 'payoff': 25000, 'rebate': 0} | Passed |
| control 3 | {'earned': 100, 'payoff': 38889, 'rebate': 0} | {'earned': 100, 'payoff': 38889, 'rebate': 0} | Passed |
| control 4 | {'earned': 100, 'payoff': 60000, 'rebate': 0} | {'earned': 100, 'payoff': 60000, 'rebate': 0} | Passed |
| control 5 | {'earned': 7777, 'payoff': 51852, 'rebate': 0} | {'earned': 7777, 'payoff': 51852, 'rebate': 0} | Passed |
| control 6 | {'earned': 7777, 'payoff': 0, 'rebate': 0} | {'earned': 7777, 'payoff': 0, 'rebate': 0} | Passed |
SHA-256 / e0f9c4d912e67af3afe68a3d01b673e4d2798628fd44864b55e69c22101b5494
Verification & scope
A deterministic bounded teaching model with stipulated toy lending rules stated in the contract; money is integer cents and rates are basis points; it makes no claim of conformance to any regulation, servicing standard or product. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:46:28.490413+00:00.
Case digest / 710f3f5c625ad6a4bae9c815d927f2cf5d7fe4b3f6ab864856e95b115abeff96