FA-58576 / Loan amortization schedules / Open access
Balloon maturity payment: maturity month · case 01
Loans whose amortization ends before the term keep charging payments into negative balances.
ROOT CAUSE
The schedule always runs to the term.
VERIFIED REPAIR
End at the earlier of term and amortization end.
Unsuccessful approach: Ending a month early drops a payment from every schedule.
Case contract
x = {'principal', 'rate_bp', 'amort_months', 'term_months'}. The level payment amortizes over amort_months (exact annuity, half-up). Payments run to the earlier of term and amortization end; the last one pays balance + interest (the balloon). Monthly interest is round_half_up(balance*bp/120000). Return {'payment', 'final_payment', 'balloon_excess': final - payment, 'total_interest'}.
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
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
def rnd(n, d):
q, r = divmod(n, d)
return q + (1 if 2 * r >= d else 0)
def level(P, n):
if n <= 0 or P <= 0:
return 0
if bp == 0:
exact = Fraction(P, n)
else:
r = Fraction(bp, 120000)
exact = P * r / (1 - (1 + r) ** -n)
return math.floor(exact + Fraction(1, 2))
bp = x['rate_bp']
P = x['principal']
pay = level(P, x['amort_months'])
last_k = x['term_months']
bal = P
total = 0
final = 0
for k in range(1, last_k + 1):
interest = rnd(bal * bp, 120000)
total += interest
if k == last_k:
final = bal + interest
else:
bal -= pay - interest
return {'payment': pay, 'final_payment': final, 'balloon_excess': final - pay, 'total_interest': total}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: maturity month', {'principal': 55555, 'rate_bp': 600, 'amort_months': 12, 'term_months': 84}, {'payment': 4781, 'final_payment': 4786, 'balloon_excess': 5, 'total_interest': 1822}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 5, 'term_months': 3}, {'payment': 20000, 'final_payment': 60000, 'balloon_excess': 40000, 'total_interest': 0}], ['control 2', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 360, 'term_months': 60}, {'payment': 5996, 'final_payment': 936506, 'balloon_excess': 930510, 'total_interest': 290270}], ['control 3', {'principal': 55555, 'rate_bp': 0, 'amort_months': 360, 'term_months': 5}, {'payment': 154, 'final_payment': 54939, 'balloon_excess': 54785, 'total_interest': 0}], ['control 4', {'principal': 100000, 'rate_bp': 725, 'amort_months': 5, 'term_months': 5}, {'payment': 20364, 'final_payment': 20364, 'balloon_excess': 0, 'total_interest': 1820}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 60, 'term_months': 3}, {'payment': 19919, 'final_payment': 978035, 'balloon_excess': 958116, 'total_interest': 17873}], ['control 6', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 5}, {'payment': 1236, 'final_payment': 53321, 'balloon_excess': 52085, 'total_interest': 2710}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 600, 'amort_months': 12, 'term_months': 60}, {'payment': 4781, 'final_payment': 4786, 'balloon_excess': 5, 'total_interest': 1822}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 12, 'term_months': 5}, {'payment': 8333, 'final_payment': 66668, 'balloon_excess': 58335, 'total_interest': 0}], ['control 2', {'principal': 100000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 5}, {'payment': 682, 'final_payment': 100288, 'balloon_excess': 99606, 'total_interest': 3016}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'amort_months': 5, 'term_months': 5}, {'payment': 20301, 'final_payment': 20300, 'balloon_excess': -1, 'total_interest': 1504}], ['control 4', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 60}, {'payment': 2224, 'final_payment': 2262, 'balloon_excess': 38, 'total_interest': 33478}], ['control 5', {'principal': 3000000, 'rate_bp': 1200, 'amort_months': 360, 'term_months': 84}, {'payment': 30858, 'final_payment': 2918745, 'balloon_excess': 2887887, 'total_interest': 2479959}], ['control 6', {'principal': 3000000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 12}, {'payment': 50000, 'final_payment': 2450000, 'balloon_excess': 2400000, 'total_interest': 0}]], [['regression: maturity month', {'principal': 1000000, 'rate_bp': 1200, 'amort_months': 5, 'term_months': 60}, {'payment': 206040, 'final_payment': 206040, 'balloon_excess': 0, 'total_interest': 30200}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 5, 'term_months': 3}, {'payment': 20000, 'final_payment': 60000, 'balloon_excess': 40000, 'total_interest': 0}], ['control 2', {'principal': 55555, 'rate_bp': 600, 'amort_months': 5, 'term_months': 3}, {'payment': 11278, 'final_payment': 33668, 'balloon_excess': 22390, 'total_interest': 669}], ['control 3', {'principal': 100000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 5}, {'payment': 1667, 'final_payment': 93332, 'balloon_excess': 91665, 'total_interest': 0}], ['control 4', {'principal': 100000, 'rate_bp': 600, 'amort_months': 12, 'term_months': 3}, {'payment': 8607, 'final_payment': 84164, 'balloon_excess': 75557, 'total_interest': 1378}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 12}, {'payment': 8885, 'final_payment': 8884, 'balloon_excess': -1, 'total_interest': 6619}], ['control 6', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 60, 'term_months': 5}, {'payment': 19333, 'final_payment': 946947, 'balloon_excess': 927614, 'total_interest': 24279}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 0, 'amort_months': 5, 'term_months': 84}, {'payment': 11111, 'final_payment': 11111, 'balloon_excess': 0, 'total_interest': 0}], ['control 1', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 12}, {'payment': 6822, 'final_payment': 997140, 'balloon_excess': 990318, 'total_interest': 72182}], ['control 2', {'principal': 1000000, 'rate_bp': 1200, 'amort_months': 360, 'term_months': 12}, {'payment': 10286, 'final_payment': 1006656, 'balloon_excess': 996370, 'total_interest': 119802}], ['control 3', {'principal': 55555, 'rate_bp': 725, 'amort_months': 360, 'term_months': 5}, {'payment': 379, 'final_payment': 55715, 'balloon_excess': 55336, 'total_interest': 1676}], ['control 4', {'principal': 1000000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 3}, {'payment': 16667, 'final_payment': 966666, 'balloon_excess': 949999, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 5, 'term_months': 5}, {'payment': 203010, 'final_payment': 203010, 'balloon_excess': 0, 'total_interest': 15050}], ['control 6', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 5, 'term_months': 3}, {'payment': 11447, 'final_payment': 34001, 'balloon_excess': 22554, 'total_interest': 1340}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 60}, {'payment': 4936, 'final_payment': 4938, 'balloon_excess': 2, 'total_interest': 3679}], ['control 1', {'principal': 3000000, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 12}, {'payment': 66733, 'final_payment': 2600867, 'balloon_excess': 2534134, 'total_interest': 334930}], ['control 2', {'principal': 55555, 'rate_bp': 725, 'amort_months': 12, 'term_months': 3}, {'payment': 4813, 'final_payment': 46855, 'balloon_excess': 42042, 'total_interest': 926}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'amort_months': 60, 'term_months': 60}, {'payment': 1933, 'final_payment': 1952, 'balloon_excess': 19, 'total_interest': 15999}], ['control 4', {'principal': 55555, 'rate_bp': 0, 'amort_months': 60, 'term_months': 60}, {'payment': 926, 'final_payment': 921, 'balloon_excess': -5, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 60}, {'payment': 6822, 'final_payment': 950593, 'balloon_excess': 943771, 'total_interest': 353091}], ['control 6', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 12}, {'payment': 8885, 'final_payment': 8884, 'balloon_excess': -1, 'total_interest': 6619}]]]
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: maturity month | {'balloon_excess': -413117, 'final_payment': -408336, 'payment': 4781, 'total_interest': -67068} | {'balloon_excess': 5, 'final_payment': 4786, 'payment': 4781, 'total_interest': 1822} | Failed |
| control 1 | {'balloon_excess': 40000, 'final_payment': 60000, 'payment': 20000, 'total_interest': 0} | {'balloon_excess': 40000, 'final_payment': 60000, 'payment': 20000, 'total_interest': 0} | Passed |
| control 2 | {'balloon_excess': 930510, 'final_payment': 936506, 'payment': 5996, 'total_interest': 290270} | {'balloon_excess': 930510, 'final_payment': 936506, 'payment': 5996, 'total_interest': 290270} | Passed |
| control 3 | {'balloon_excess': 54785, 'final_payment': 54939, 'payment': 154, 'total_interest': 0} | {'balloon_excess': 54785, 'final_payment': 54939, 'payment': 154, 'total_interest': 0} | Passed |
| control 4 | {'balloon_excess': 0, 'final_payment': 20364, 'payment': 20364, 'total_interest': 1820} | {'balloon_excess': 0, 'final_payment': 20364, 'payment': 20364, 'total_interest': 1820} | Passed |
| control 5 | {'balloon_excess': 958116, 'final_payment': 978035, 'payment': 19919, 'total_interest': 17873} | {'balloon_excess': 958116, 'final_payment': 978035, 'payment': 19919, 'total_interest': 17873} | Passed |
| control 6 | {'balloon_excess': 52085, 'final_payment': 53321, 'payment': 1236, 'total_interest': 2710} | {'balloon_excess': 52085, 'final_payment': 53321, 'payment': 1236, 'total_interest': 2710} | Passed |
SHA-256 / 8058fb3a5191d4463113e0032a11b5af982039fcebea9e1737d110dbfa0fda49
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
def rnd(n, d):
q, r = divmod(n, d)
return q + (1 if 2 * r >= d else 0)
def level(P, n):
if n <= 0 or P <= 0:
return 0
if bp == 0:
exact = Fraction(P, n)
else:
r = Fraction(bp, 120000)
exact = P * r / (1 - (1 + r) ** -n)
return math.floor(exact + Fraction(1, 2))
bp = x['rate_bp']
P = x['principal']
pay = level(P, x['amort_months'])
last_k = min(x['term_months'], x['amort_months']) - 1
bal = P
total = 0
final = 0
for k in range(1, last_k + 1):
interest = rnd(bal * bp, 120000)
total += interest
if k == last_k:
final = bal + interest
else:
bal -= pay - interest
return {'payment': pay, 'final_payment': final, 'balloon_excess': final - pay, 'total_interest': total}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: maturity month', {'principal': 55555, 'rate_bp': 600, 'amort_months': 12, 'term_months': 84}, {'payment': 4781, 'final_payment': 4786, 'balloon_excess': 5, 'total_interest': 1822}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 5, 'term_months': 3}, {'payment': 20000, 'final_payment': 60000, 'balloon_excess': 40000, 'total_interest': 0}], ['control 2', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 360, 'term_months': 60}, {'payment': 5996, 'final_payment': 936506, 'balloon_excess': 930510, 'total_interest': 290270}], ['control 3', {'principal': 55555, 'rate_bp': 0, 'amort_months': 360, 'term_months': 5}, {'payment': 154, 'final_payment': 54939, 'balloon_excess': 54785, 'total_interest': 0}], ['control 4', {'principal': 100000, 'rate_bp': 725, 'amort_months': 5, 'term_months': 5}, {'payment': 20364, 'final_payment': 20364, 'balloon_excess': 0, 'total_interest': 1820}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 60, 'term_months': 3}, {'payment': 19919, 'final_payment': 978035, 'balloon_excess': 958116, 'total_interest': 17873}], ['control 6', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 5}, {'payment': 1236, 'final_payment': 53321, 'balloon_excess': 52085, 'total_interest': 2710}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 600, 'amort_months': 12, 'term_months': 60}, {'payment': 4781, 'final_payment': 4786, 'balloon_excess': 5, 'total_interest': 1822}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 12, 'term_months': 5}, {'payment': 8333, 'final_payment': 66668, 'balloon_excess': 58335, 'total_interest': 0}], ['control 2', {'principal': 100000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 5}, {'payment': 682, 'final_payment': 100288, 'balloon_excess': 99606, 'total_interest': 3016}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'amort_months': 5, 'term_months': 5}, {'payment': 20301, 'final_payment': 20300, 'balloon_excess': -1, 'total_interest': 1504}], ['control 4', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 60}, {'payment': 2224, 'final_payment': 2262, 'balloon_excess': 38, 'total_interest': 33478}], ['control 5', {'principal': 3000000, 'rate_bp': 1200, 'amort_months': 360, 'term_months': 84}, {'payment': 30858, 'final_payment': 2918745, 'balloon_excess': 2887887, 'total_interest': 2479959}], ['control 6', {'principal': 3000000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 12}, {'payment': 50000, 'final_payment': 2450000, 'balloon_excess': 2400000, 'total_interest': 0}]], [['regression: maturity month', {'principal': 1000000, 'rate_bp': 1200, 'amort_months': 5, 'term_months': 60}, {'payment': 206040, 'final_payment': 206040, 'balloon_excess': 0, 'total_interest': 30200}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 5, 'term_months': 3}, {'payment': 20000, 'final_payment': 60000, 'balloon_excess': 40000, 'total_interest': 0}], ['control 2', {'principal': 55555, 'rate_bp': 600, 'amort_months': 5, 'term_months': 3}, {'payment': 11278, 'final_payment': 33668, 'balloon_excess': 22390, 'total_interest': 669}], ['control 3', {'principal': 100000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 5}, {'payment': 1667, 'final_payment': 93332, 'balloon_excess': 91665, 'total_interest': 0}], ['control 4', {'principal': 100000, 'rate_bp': 600, 'amort_months': 12, 'term_months': 3}, {'payment': 8607, 'final_payment': 84164, 'balloon_excess': 75557, 'total_interest': 1378}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 12}, {'payment': 8885, 'final_payment': 8884, 'balloon_excess': -1, 'total_interest': 6619}], ['control 6', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 60, 'term_months': 5}, {'payment': 19333, 'final_payment': 946947, 'balloon_excess': 927614, 'total_interest': 24279}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 0, 'amort_months': 5, 'term_months': 84}, {'payment': 11111, 'final_payment': 11111, 'balloon_excess': 0, 'total_interest': 0}], ['control 1', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 12}, {'payment': 6822, 'final_payment': 997140, 'balloon_excess': 990318, 'total_interest': 72182}], ['control 2', {'principal': 1000000, 'rate_bp': 1200, 'amort_months': 360, 'term_months': 12}, {'payment': 10286, 'final_payment': 1006656, 'balloon_excess': 996370, 'total_interest': 119802}], ['control 3', {'principal': 55555, 'rate_bp': 725, 'amort_months': 360, 'term_months': 5}, {'payment': 379, 'final_payment': 55715, 'balloon_excess': 55336, 'total_interest': 1676}], ['control 4', {'principal': 1000000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 3}, {'payment': 16667, 'final_payment': 966666, 'balloon_excess': 949999, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 5, 'term_months': 5}, {'payment': 203010, 'final_payment': 203010, 'balloon_excess': 0, 'total_interest': 15050}], ['control 6', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 5, 'term_months': 3}, {'payment': 11447, 'final_payment': 34001, 'balloon_excess': 22554, 'total_interest': 1340}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 60}, {'payment': 4936, 'final_payment': 4938, 'balloon_excess': 2, 'total_interest': 3679}], ['control 1', {'principal': 3000000, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 12}, {'payment': 66733, 'final_payment': 2600867, 'balloon_excess': 2534134, 'total_interest': 334930}], ['control 2', {'principal': 55555, 'rate_bp': 725, 'amort_months': 12, 'term_months': 3}, {'payment': 4813, 'final_payment': 46855, 'balloon_excess': 42042, 'total_interest': 926}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'amort_months': 60, 'term_months': 60}, {'payment': 1933, 'final_payment': 1952, 'balloon_excess': 19, 'total_interest': 15999}], ['control 4', {'principal': 55555, 'rate_bp': 0, 'amort_months': 60, 'term_months': 60}, {'payment': 926, 'final_payment': 921, 'balloon_excess': -5, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 60}, {'payment': 6822, 'final_payment': 950593, 'balloon_excess': 943771, 'total_interest': 353091}], ['control 6', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 12}, {'payment': 8885, 'final_payment': 8884, 'balloon_excess': -1, 'total_interest': 6619}]]]
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: maturity month | {'balloon_excess': 4762, 'final_payment': 9543, 'payment': 4781, 'total_interest': 1798} | {'balloon_excess': 5, 'final_payment': 4786, 'payment': 4781, 'total_interest': 1822} | Failed |
| control 1 | {'balloon_excess': 60000, 'final_payment': 80000, 'payment': 20000, 'total_interest': 0} | {'balloon_excess': 40000, 'final_payment': 60000, 'payment': 20000, 'total_interest': 0} | Failed |
| control 2 | {'balloon_excess': 931847, 'final_payment': 937843, 'payment': 5996, 'total_interest': 285611} | {'balloon_excess': 930510, 'final_payment': 936506, 'payment': 5996, 'total_interest': 290270} | Failed |
| control 3 | {'balloon_excess': 54939, 'final_payment': 55093, 'payment': 154, 'total_interest': 0} | {'balloon_excess': 54785, 'final_payment': 54939, 'payment': 154, 'total_interest': 0} | Failed |
| control 4 | {'balloon_excess': 20242, 'final_payment': 40606, 'payment': 20364, 'total_interest': 1698} | {'balloon_excess': 0, 'final_payment': 20364, 'payment': 20364, 'total_interest': 1820} | Failed |
| control 5 | {'balloon_excess': 972162, 'final_payment': 992081, 'payment': 19919, 'total_interest': 12000} | {'balloon_excess': 958116, 'final_payment': 978035, 'payment': 19919, 'total_interest': 17873} | Failed |
| control 6 | {'balloon_excess': 52793, 'final_payment': 54029, 'payment': 1236, 'total_interest': 2182} | {'balloon_excess': 52085, 'final_payment': 53321, 'payment': 1236, 'total_interest': 2710} | Failed |
SHA-256 / aba11e40cb0468cb7a9b20660efde25e802f404c161cb300f4eb633d28769be6
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
def rnd(n, d):
q, r = divmod(n, d)
return q + (1 if 2 * r >= d else 0)
def level(P, n):
if n <= 0 or P <= 0:
return 0
if bp == 0:
exact = Fraction(P, n)
else:
r = Fraction(bp, 120000)
exact = P * r / (1 - (1 + r) ** -n)
return math.floor(exact + Fraction(1, 2))
bp = x['rate_bp']
P = x['principal']
pay = level(P, x['amort_months'])
last_k = min(x['term_months'], x['amort_months'])
bal = P
total = 0
final = 0
for k in range(1, last_k + 1):
interest = rnd(bal * bp, 120000)
total += interest
if k == last_k:
final = bal + interest
else:
bal -= pay - interest
return {'payment': pay, 'final_payment': final, 'balloon_excess': final - pay, 'total_interest': total}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: maturity month', {'principal': 55555, 'rate_bp': 600, 'amort_months': 12, 'term_months': 84}, {'payment': 4781, 'final_payment': 4786, 'balloon_excess': 5, 'total_interest': 1822}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 5, 'term_months': 3}, {'payment': 20000, 'final_payment': 60000, 'balloon_excess': 40000, 'total_interest': 0}], ['control 2', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 360, 'term_months': 60}, {'payment': 5996, 'final_payment': 936506, 'balloon_excess': 930510, 'total_interest': 290270}], ['control 3', {'principal': 55555, 'rate_bp': 0, 'amort_months': 360, 'term_months': 5}, {'payment': 154, 'final_payment': 54939, 'balloon_excess': 54785, 'total_interest': 0}], ['control 4', {'principal': 100000, 'rate_bp': 725, 'amort_months': 5, 'term_months': 5}, {'payment': 20364, 'final_payment': 20364, 'balloon_excess': 0, 'total_interest': 1820}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 60, 'term_months': 3}, {'payment': 19919, 'final_payment': 978035, 'balloon_excess': 958116, 'total_interest': 17873}], ['control 6', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 5}, {'payment': 1236, 'final_payment': 53321, 'balloon_excess': 52085, 'total_interest': 2710}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 600, 'amort_months': 12, 'term_months': 60}, {'payment': 4781, 'final_payment': 4786, 'balloon_excess': 5, 'total_interest': 1822}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 12, 'term_months': 5}, {'payment': 8333, 'final_payment': 66668, 'balloon_excess': 58335, 'total_interest': 0}], ['control 2', {'principal': 100000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 5}, {'payment': 682, 'final_payment': 100288, 'balloon_excess': 99606, 'total_interest': 3016}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'amort_months': 5, 'term_months': 5}, {'payment': 20301, 'final_payment': 20300, 'balloon_excess': -1, 'total_interest': 1504}], ['control 4', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 60}, {'payment': 2224, 'final_payment': 2262, 'balloon_excess': 38, 'total_interest': 33478}], ['control 5', {'principal': 3000000, 'rate_bp': 1200, 'amort_months': 360, 'term_months': 84}, {'payment': 30858, 'final_payment': 2918745, 'balloon_excess': 2887887, 'total_interest': 2479959}], ['control 6', {'principal': 3000000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 12}, {'payment': 50000, 'final_payment': 2450000, 'balloon_excess': 2400000, 'total_interest': 0}]], [['regression: maturity month', {'principal': 1000000, 'rate_bp': 1200, 'amort_months': 5, 'term_months': 60}, {'payment': 206040, 'final_payment': 206040, 'balloon_excess': 0, 'total_interest': 30200}], ['control 1', {'principal': 100000, 'rate_bp': 0, 'amort_months': 5, 'term_months': 3}, {'payment': 20000, 'final_payment': 60000, 'balloon_excess': 40000, 'total_interest': 0}], ['control 2', {'principal': 55555, 'rate_bp': 600, 'amort_months': 5, 'term_months': 3}, {'payment': 11278, 'final_payment': 33668, 'balloon_excess': 22390, 'total_interest': 669}], ['control 3', {'principal': 100000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 5}, {'payment': 1667, 'final_payment': 93332, 'balloon_excess': 91665, 'total_interest': 0}], ['control 4', {'principal': 100000, 'rate_bp': 600, 'amort_months': 12, 'term_months': 3}, {'payment': 8607, 'final_payment': 84164, 'balloon_excess': 75557, 'total_interest': 1378}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 12}, {'payment': 8885, 'final_payment': 8884, 'balloon_excess': -1, 'total_interest': 6619}], ['control 6', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 60, 'term_months': 5}, {'payment': 19333, 'final_payment': 946947, 'balloon_excess': 927614, 'total_interest': 24279}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 0, 'amort_months': 5, 'term_months': 84}, {'payment': 11111, 'final_payment': 11111, 'balloon_excess': 0, 'total_interest': 0}], ['control 1', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 12}, {'payment': 6822, 'final_payment': 997140, 'balloon_excess': 990318, 'total_interest': 72182}], ['control 2', {'principal': 1000000, 'rate_bp': 1200, 'amort_months': 360, 'term_months': 12}, {'payment': 10286, 'final_payment': 1006656, 'balloon_excess': 996370, 'total_interest': 119802}], ['control 3', {'principal': 55555, 'rate_bp': 725, 'amort_months': 360, 'term_months': 5}, {'payment': 379, 'final_payment': 55715, 'balloon_excess': 55336, 'total_interest': 1676}], ['control 4', {'principal': 1000000, 'rate_bp': 0, 'amort_months': 60, 'term_months': 3}, {'payment': 16667, 'final_payment': 966666, 'balloon_excess': 949999, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 600, 'amort_months': 5, 'term_months': 5}, {'payment': 203010, 'final_payment': 203010, 'balloon_excess': 0, 'total_interest': 15050}], ['control 6', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 5, 'term_months': 3}, {'payment': 11447, 'final_payment': 34001, 'balloon_excess': 22554, 'total_interest': 1340}]], [['regression: maturity month', {'principal': 55555, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 60}, {'payment': 4936, 'final_payment': 4938, 'balloon_excess': 2, 'total_interest': 3679}], ['control 1', {'principal': 3000000, 'rate_bp': 1200, 'amort_months': 60, 'term_months': 12}, {'payment': 66733, 'final_payment': 2600867, 'balloon_excess': 2534134, 'total_interest': 334930}], ['control 2', {'principal': 55555, 'rate_bp': 725, 'amort_months': 12, 'term_months': 3}, {'payment': 4813, 'final_payment': 46855, 'balloon_excess': 42042, 'total_interest': 926}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'amort_months': 60, 'term_months': 60}, {'payment': 1933, 'final_payment': 1952, 'balloon_excess': 19, 'total_interest': 15999}], ['control 4', {'principal': 55555, 'rate_bp': 0, 'amort_months': 60, 'term_months': 60}, {'payment': 926, 'final_payment': 921, 'balloon_excess': -5, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'amort_months': 360, 'term_months': 60}, {'payment': 6822, 'final_payment': 950593, 'balloon_excess': 943771, 'total_interest': 353091}], ['control 6', {'principal': 100000, 'rate_bp': 1200, 'amort_months': 12, 'term_months': 12}, {'payment': 8885, 'final_payment': 8884, 'balloon_excess': -1, 'total_interest': 6619}]]]
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: maturity month | {'balloon_excess': 5, 'final_payment': 4786, 'payment': 4781, 'total_interest': 1822} | {'balloon_excess': 5, 'final_payment': 4786, 'payment': 4781, 'total_interest': 1822} | Passed |
| control 1 | {'balloon_excess': 40000, 'final_payment': 60000, 'payment': 20000, 'total_interest': 0} | {'balloon_excess': 40000, 'final_payment': 60000, 'payment': 20000, 'total_interest': 0} | Passed |
| control 2 | {'balloon_excess': 930510, 'final_payment': 936506, 'payment': 5996, 'total_interest': 290270} | {'balloon_excess': 930510, 'final_payment': 936506, 'payment': 5996, 'total_interest': 290270} | Passed |
| control 3 | {'balloon_excess': 54785, 'final_payment': 54939, 'payment': 154, 'total_interest': 0} | {'balloon_excess': 54785, 'final_payment': 54939, 'payment': 154, 'total_interest': 0} | Passed |
| control 4 | {'balloon_excess': 0, 'final_payment': 20364, 'payment': 20364, 'total_interest': 1820} | {'balloon_excess': 0, 'final_payment': 20364, 'payment': 20364, 'total_interest': 1820} | Passed |
| control 5 | {'balloon_excess': 958116, 'final_payment': 978035, 'payment': 19919, 'total_interest': 17873} | {'balloon_excess': 958116, 'final_payment': 978035, 'payment': 19919, 'total_interest': 17873} | Passed |
| control 6 | {'balloon_excess': 52085, 'final_payment': 53321, 'payment': 1236, 'total_interest': 2710} | {'balloon_excess': 52085, 'final_payment': 53321, 'payment': 1236, 'total_interest': 2710} | Passed |
SHA-256 / 356da49856ce83c3feec804fec3798b8d2cbc20b7d598eca861ea05cf4b59712
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.062658+00:00.
Case digest / b36de66d9392e890329e311e4b41aa23a9c623692d8872f3fa005e7d975c850a