FA-58371 / Loan amortization schedules / Open access
Level payment with final adjustment: final payment amount · case 01
The last payment ignores the rounding residue left in the balance.
ROOT CAUSE
The final payment is set to the level payment.
VERIFIED REPAIR
Make the final payment the remaining balance plus that month interest.
Unsuccessful approach: Paying only the remaining balance omits the final month interest.
Case contract
x = {'principal', 'rate_bp' (annual, monthly rate = bp/120000), 'months', 'round': 'nearest'|'up'}. The exact annuity payment P*r/(1-(1+r)^-n) (P/n at zero rate) is rounded half-up ('nearest') or up to the cent. Monthly interest is round_half_up(balance*bp/120000); months 1..n-1 pay the level payment and month n pays balance + interest. Return {'payment', '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):
P = x['principal']
n = x['months']
bp = x['rate_bp']
if bp == 0:
exact = Fraction(P, n)
else:
r = Fraction(bp, 120000)
exact = P * r / (1 - (1 + r) ** -n)
if x['round'] == 'up':
pay = math.ceil(exact)
else:
pay = math.floor(exact + Fraction(1, 2))
bal = P
total_int = 0
last = 0
for k in range(1, n + 1):
q, rem = divmod(bal * bp, 120000)
interest = q + (1 if 2 * rem >= 120000 else 0)
total_int += interest
if k == n:
last = pay
else:
bal = bal + interest - pay
return {'payment': pay, 'final_payment': last, 'total_interest': total_int}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: final payment amount', {'principal': 7, 'rate_bp': 725, 'months': 360, 'round': 'up'}, {'payment': 1, 'final_payment': -1123, 'total_interest': -771}], ['control 1', {'principal': 12345, 'rate_bp': 1200, 'months': 1, 'round': 'nearest'}, {'payment': 12468, 'final_payment': 12468, 'total_interest': 123}], ['control 2', {'principal': 100000, 'rate_bp': 600, 'months': 7, 'round': 'nearest'}, {'payment': 14573, 'final_payment': 14573, 'total_interest': 2011}], ['control 3', {'principal': 999999, 'rate_bp': 725, 'months': 3, 'round': 'up'}, {'payment': 337369, 'final_payment': 337369, 'total_interest': 12108}], ['control 4', {'principal': 500, 'rate_bp': 0, 'months': 2, 'round': 'nearest'}, {'payment': 250, 'final_payment': 250, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'months': 2, 'round': 'nearest'}, {'payment': 504536, 'final_payment': 504536, 'total_interest': 9072}], ['control 6', {'principal': 999999, 'rate_bp': 725, 'months': 3, 'round': 'nearest'}, {'payment': 337369, 'final_payment': 337369, 'total_interest': 12108}]], [['regression: final payment amount', {'principal': 500, 'rate_bp': 13, 'months': 3, 'round': 'up'}, {'payment': 167, 'final_payment': 166, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 2500000, 'rate_bp': 1999, 'months': 3, 'round': 'nearest'}, {'payment': 861250, 'final_payment': 861251, 'total_interest': 83751}], ['control 1', {'principal': 999999, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 333333, 'final_payment': 333333, 'total_interest': 0}], ['control 2', {'principal': 1000000, 'rate_bp': 725, 'months': 1, 'round': 'nearest'}, {'payment': 1006042, 'final_payment': 1006042, 'total_interest': 6042}], ['control 3', {'principal': 999999, 'rate_bp': 1200, 'months': 3, 'round': 'up'}, {'payment': 340022, 'final_payment': 340022, 'total_interest': 20067}], ['control 4', {'principal': 999999, 'rate_bp': 0, 'months': 1, 'round': 'nearest'}, {'payment': 999999, 'final_payment': 999999, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 1000000, 'final_payment': 1000000, 'total_interest': 0}]], [['regression: final payment amount', {'principal': 999999, 'rate_bp': 0, 'months': 12, 'round': 'nearest'}, {'payment': 83333, 'final_payment': 83336, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 2500000, 'rate_bp': 13, 'months': 1, 'round': 'nearest'}, {'payment': 2500271, 'final_payment': 2500271, 'total_interest': 271}], ['control 1', {'principal': 100000, 'rate_bp': 1999, 'months': 3, 'round': 'nearest'}, {'payment': 34450, 'final_payment': 34450, 'total_interest': 3350}], ['control 2', {'principal': 500, 'rate_bp': 1200, 'months': 3, 'round': 'nearest'}, {'payment': 170, 'final_payment': 170, 'total_interest': 10}], ['control 3', {'principal': 12345, 'rate_bp': 1200, 'months': 2, 'round': 'nearest'}, {'payment': 6265, 'final_payment': 6265, 'total_interest': 185}], ['control 4', {'principal': 500, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 500, 'final_payment': 500, 'total_interest': 0}], ['control 5', {'principal': 500, 'rate_bp': 499, 'months': 1, 'round': 'nearest'}, {'payment': 502, 'final_payment': 502, 'total_interest': 2}]], [['regression: final payment amount', {'principal': 7, 'rate_bp': 13, 'months': 12, 'round': 'up'}, {'payment': 1, 'final_payment': -4, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 1000000, 'rate_bp': 13, 'months': 60, 'round': 'up'}, {'payment': 16722, 'final_payment': 16710, 'total_interest': 3308}], ['control 1', {'principal': 7, 'rate_bp': 1999, 'months': 7, 'round': 'nearest'}, {'payment': 1, 'final_payment': 1, 'total_interest': 0}], ['control 2', {'principal': 30000000, 'rate_bp': 0, 'months': 12, 'round': 'up'}, {'payment': 2500000, 'final_payment': 2500000, 'total_interest': 0}], ['control 3', {'principal': 30000000, 'rate_bp': 600, 'months': 1, 'round': 'up'}, {'payment': 30150000, 'final_payment': 30150000, 'total_interest': 150000}], ['control 4', {'principal': 12345, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 4115, 'final_payment': 4115, 'total_interest': 0}], ['control 5', {'principal': 30000000, 'rate_bp': 1999, 'months': 1, 'round': 'nearest'}, {'payment': 30499750, 'final_payment': 30499750, 'total_interest': 499750}]], [['regression: final payment amount', {'principal': 7, 'rate_bp': 600, 'months': 360, 'round': 'up'}, {'payment': 1, 'final_payment': -876, 'total_interest': -524}], ['control 1', {'principal': 30000000, 'rate_bp': 499, 'months': 2, 'round': 'nearest'}, {'payment': 15093627, 'final_payment': 15093627, 'total_interest': 187254}], ['control 2', {'principal': 999999, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 333333, 'final_payment': 333333, 'total_interest': 0}], ['control 3', {'principal': 500, 'rate_bp': 0, 'months': 2, 'round': 'up'}, {'payment': 250, 'final_payment': 250, 'total_interest': 0}], ['control 4', {'principal': 2500000, 'rate_bp': 499, 'months': 1, 'round': 'nearest'}, {'payment': 2510396, 'final_payment': 2510396, 'total_interest': 10396}], ['control 5', {'principal': 100000, 'rate_bp': 13, 'months': 1, 'round': 'nearest'}, {'payment': 100011, 'final_payment': 100011, 'total_interest': 11}], ['control 6', {'principal': 100000, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 100000, 'final_payment': 100000, 'total_interest': 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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: final payment amount | {'final_payment': 1, 'payment': 1, 'total_interest': -771} | {'final_payment': -1123, 'payment': 1, 'total_interest': -771} | Failed |
| control 1 | {'final_payment': 12468, 'payment': 12468, 'total_interest': 123} | {'final_payment': 12468, 'payment': 12468, 'total_interest': 123} | Passed |
| control 2 | {'final_payment': 14573, 'payment': 14573, 'total_interest': 2011} | {'final_payment': 14573, 'payment': 14573, 'total_interest': 2011} | Passed |
| control 3 | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | Passed |
| control 4 | {'final_payment': 250, 'payment': 250, 'total_interest': 0} | {'final_payment': 250, 'payment': 250, 'total_interest': 0} | Passed |
| control 5 | {'final_payment': 504536, 'payment': 504536, 'total_interest': 9072} | {'final_payment': 504536, 'payment': 504536, 'total_interest': 9072} | Passed |
| control 6 | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | Passed |
SHA-256 / c638342752b5f528836a96f2cf35c619e8f43ece932f06bed9818087d40b2e00
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):
P = x['principal']
n = x['months']
bp = x['rate_bp']
if bp == 0:
exact = Fraction(P, n)
else:
r = Fraction(bp, 120000)
exact = P * r / (1 - (1 + r) ** -n)
if x['round'] == 'up':
pay = math.ceil(exact)
else:
pay = math.floor(exact + Fraction(1, 2))
bal = P
total_int = 0
last = 0
for k in range(1, n + 1):
q, rem = divmod(bal * bp, 120000)
interest = q + (1 if 2 * rem >= 120000 else 0)
total_int += interest
if k == n:
last = bal
else:
bal = bal + interest - pay
return {'payment': pay, 'final_payment': last, 'total_interest': total_int}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: final payment amount', {'principal': 7, 'rate_bp': 725, 'months': 360, 'round': 'up'}, {'payment': 1, 'final_payment': -1123, 'total_interest': -771}], ['control 1', {'principal': 12345, 'rate_bp': 1200, 'months': 1, 'round': 'nearest'}, {'payment': 12468, 'final_payment': 12468, 'total_interest': 123}], ['control 2', {'principal': 100000, 'rate_bp': 600, 'months': 7, 'round': 'nearest'}, {'payment': 14573, 'final_payment': 14573, 'total_interest': 2011}], ['control 3', {'principal': 999999, 'rate_bp': 725, 'months': 3, 'round': 'up'}, {'payment': 337369, 'final_payment': 337369, 'total_interest': 12108}], ['control 4', {'principal': 500, 'rate_bp': 0, 'months': 2, 'round': 'nearest'}, {'payment': 250, 'final_payment': 250, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'months': 2, 'round': 'nearest'}, {'payment': 504536, 'final_payment': 504536, 'total_interest': 9072}], ['control 6', {'principal': 999999, 'rate_bp': 725, 'months': 3, 'round': 'nearest'}, {'payment': 337369, 'final_payment': 337369, 'total_interest': 12108}]], [['regression: final payment amount', {'principal': 500, 'rate_bp': 13, 'months': 3, 'round': 'up'}, {'payment': 167, 'final_payment': 166, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 2500000, 'rate_bp': 1999, 'months': 3, 'round': 'nearest'}, {'payment': 861250, 'final_payment': 861251, 'total_interest': 83751}], ['control 1', {'principal': 999999, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 333333, 'final_payment': 333333, 'total_interest': 0}], ['control 2', {'principal': 1000000, 'rate_bp': 725, 'months': 1, 'round': 'nearest'}, {'payment': 1006042, 'final_payment': 1006042, 'total_interest': 6042}], ['control 3', {'principal': 999999, 'rate_bp': 1200, 'months': 3, 'round': 'up'}, {'payment': 340022, 'final_payment': 340022, 'total_interest': 20067}], ['control 4', {'principal': 999999, 'rate_bp': 0, 'months': 1, 'round': 'nearest'}, {'payment': 999999, 'final_payment': 999999, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 1000000, 'final_payment': 1000000, 'total_interest': 0}]], [['regression: final payment amount', {'principal': 999999, 'rate_bp': 0, 'months': 12, 'round': 'nearest'}, {'payment': 83333, 'final_payment': 83336, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 2500000, 'rate_bp': 13, 'months': 1, 'round': 'nearest'}, {'payment': 2500271, 'final_payment': 2500271, 'total_interest': 271}], ['control 1', {'principal': 100000, 'rate_bp': 1999, 'months': 3, 'round': 'nearest'}, {'payment': 34450, 'final_payment': 34450, 'total_interest': 3350}], ['control 2', {'principal': 500, 'rate_bp': 1200, 'months': 3, 'round': 'nearest'}, {'payment': 170, 'final_payment': 170, 'total_interest': 10}], ['control 3', {'principal': 12345, 'rate_bp': 1200, 'months': 2, 'round': 'nearest'}, {'payment': 6265, 'final_payment': 6265, 'total_interest': 185}], ['control 4', {'principal': 500, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 500, 'final_payment': 500, 'total_interest': 0}], ['control 5', {'principal': 500, 'rate_bp': 499, 'months': 1, 'round': 'nearest'}, {'payment': 502, 'final_payment': 502, 'total_interest': 2}]], [['regression: final payment amount', {'principal': 7, 'rate_bp': 13, 'months': 12, 'round': 'up'}, {'payment': 1, 'final_payment': -4, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 1000000, 'rate_bp': 13, 'months': 60, 'round': 'up'}, {'payment': 16722, 'final_payment': 16710, 'total_interest': 3308}], ['control 1', {'principal': 7, 'rate_bp': 1999, 'months': 7, 'round': 'nearest'}, {'payment': 1, 'final_payment': 1, 'total_interest': 0}], ['control 2', {'principal': 30000000, 'rate_bp': 0, 'months': 12, 'round': 'up'}, {'payment': 2500000, 'final_payment': 2500000, 'total_interest': 0}], ['control 3', {'principal': 30000000, 'rate_bp': 600, 'months': 1, 'round': 'up'}, {'payment': 30150000, 'final_payment': 30150000, 'total_interest': 150000}], ['control 4', {'principal': 12345, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 4115, 'final_payment': 4115, 'total_interest': 0}], ['control 5', {'principal': 30000000, 'rate_bp': 1999, 'months': 1, 'round': 'nearest'}, {'payment': 30499750, 'final_payment': 30499750, 'total_interest': 499750}]], [['regression: final payment amount', {'principal': 7, 'rate_bp': 600, 'months': 360, 'round': 'up'}, {'payment': 1, 'final_payment': -876, 'total_interest': -524}], ['control 1', {'principal': 30000000, 'rate_bp': 499, 'months': 2, 'round': 'nearest'}, {'payment': 15093627, 'final_payment': 15093627, 'total_interest': 187254}], ['control 2', {'principal': 999999, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 333333, 'final_payment': 333333, 'total_interest': 0}], ['control 3', {'principal': 500, 'rate_bp': 0, 'months': 2, 'round': 'up'}, {'payment': 250, 'final_payment': 250, 'total_interest': 0}], ['control 4', {'principal': 2500000, 'rate_bp': 499, 'months': 1, 'round': 'nearest'}, {'payment': 2510396, 'final_payment': 2510396, 'total_interest': 10396}], ['control 5', {'principal': 100000, 'rate_bp': 13, 'months': 1, 'round': 'nearest'}, {'payment': 100011, 'final_payment': 100011, 'total_interest': 11}], ['control 6', {'principal': 100000, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 100000, 'final_payment': 100000, 'total_interest': 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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: final payment amount | {'final_payment': -1116, 'payment': 1, 'total_interest': -771} | {'final_payment': -1123, 'payment': 1, 'total_interest': -771} | Failed |
| control 1 | {'final_payment': 12345, 'payment': 12468, 'total_interest': 123} | {'final_payment': 12468, 'payment': 12468, 'total_interest': 123} | Failed |
| control 2 | {'final_payment': 14500, 'payment': 14573, 'total_interest': 2011} | {'final_payment': 14573, 'payment': 14573, 'total_interest': 2011} | Failed |
| control 3 | {'final_payment': 335343, 'payment': 337369, 'total_interest': 12108} | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | Failed |
| control 4 | {'final_payment': 250, 'payment': 250, 'total_interest': 0} | {'final_payment': 250, 'payment': 250, 'total_interest': 0} | Passed |
| control 5 | {'final_payment': 501506, 'payment': 504536, 'total_interest': 9072} | {'final_payment': 504536, 'payment': 504536, 'total_interest': 9072} | Failed |
| control 6 | {'final_payment': 335343, 'payment': 337369, 'total_interest': 12108} | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | Failed |
SHA-256 / 9d1509ef215a56f444ec3c37b415ce8ef8ac7870fd0467a332be086f2522486b
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):
P = x['principal']
n = x['months']
bp = x['rate_bp']
if bp == 0:
exact = Fraction(P, n)
else:
r = Fraction(bp, 120000)
exact = P * r / (1 - (1 + r) ** -n)
if x['round'] == 'up':
pay = math.ceil(exact)
else:
pay = math.floor(exact + Fraction(1, 2))
bal = P
total_int = 0
last = 0
for k in range(1, n + 1):
q, rem = divmod(bal * bp, 120000)
interest = q + (1 if 2 * rem >= 120000 else 0)
total_int += interest
if k == n:
last = bal + interest
else:
bal = bal + interest - pay
return {'payment': pay, 'final_payment': last, 'total_interest': total_int}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: final payment amount', {'principal': 7, 'rate_bp': 725, 'months': 360, 'round': 'up'}, {'payment': 1, 'final_payment': -1123, 'total_interest': -771}], ['control 1', {'principal': 12345, 'rate_bp': 1200, 'months': 1, 'round': 'nearest'}, {'payment': 12468, 'final_payment': 12468, 'total_interest': 123}], ['control 2', {'principal': 100000, 'rate_bp': 600, 'months': 7, 'round': 'nearest'}, {'payment': 14573, 'final_payment': 14573, 'total_interest': 2011}], ['control 3', {'principal': 999999, 'rate_bp': 725, 'months': 3, 'round': 'up'}, {'payment': 337369, 'final_payment': 337369, 'total_interest': 12108}], ['control 4', {'principal': 500, 'rate_bp': 0, 'months': 2, 'round': 'nearest'}, {'payment': 250, 'final_payment': 250, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 725, 'months': 2, 'round': 'nearest'}, {'payment': 504536, 'final_payment': 504536, 'total_interest': 9072}], ['control 6', {'principal': 999999, 'rate_bp': 725, 'months': 3, 'round': 'nearest'}, {'payment': 337369, 'final_payment': 337369, 'total_interest': 12108}]], [['regression: final payment amount', {'principal': 500, 'rate_bp': 13, 'months': 3, 'round': 'up'}, {'payment': 167, 'final_payment': 166, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 2500000, 'rate_bp': 1999, 'months': 3, 'round': 'nearest'}, {'payment': 861250, 'final_payment': 861251, 'total_interest': 83751}], ['control 1', {'principal': 999999, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 333333, 'final_payment': 333333, 'total_interest': 0}], ['control 2', {'principal': 1000000, 'rate_bp': 725, 'months': 1, 'round': 'nearest'}, {'payment': 1006042, 'final_payment': 1006042, 'total_interest': 6042}], ['control 3', {'principal': 999999, 'rate_bp': 1200, 'months': 3, 'round': 'up'}, {'payment': 340022, 'final_payment': 340022, 'total_interest': 20067}], ['control 4', {'principal': 999999, 'rate_bp': 0, 'months': 1, 'round': 'nearest'}, {'payment': 999999, 'final_payment': 999999, 'total_interest': 0}], ['control 5', {'principal': 1000000, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 1000000, 'final_payment': 1000000, 'total_interest': 0}]], [['regression: final payment amount', {'principal': 999999, 'rate_bp': 0, 'months': 12, 'round': 'nearest'}, {'payment': 83333, 'final_payment': 83336, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 2500000, 'rate_bp': 13, 'months': 1, 'round': 'nearest'}, {'payment': 2500271, 'final_payment': 2500271, 'total_interest': 271}], ['control 1', {'principal': 100000, 'rate_bp': 1999, 'months': 3, 'round': 'nearest'}, {'payment': 34450, 'final_payment': 34450, 'total_interest': 3350}], ['control 2', {'principal': 500, 'rate_bp': 1200, 'months': 3, 'round': 'nearest'}, {'payment': 170, 'final_payment': 170, 'total_interest': 10}], ['control 3', {'principal': 12345, 'rate_bp': 1200, 'months': 2, 'round': 'nearest'}, {'payment': 6265, 'final_payment': 6265, 'total_interest': 185}], ['control 4', {'principal': 500, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 500, 'final_payment': 500, 'total_interest': 0}], ['control 5', {'principal': 500, 'rate_bp': 499, 'months': 1, 'round': 'nearest'}, {'payment': 502, 'final_payment': 502, 'total_interest': 2}]], [['regression: final payment amount', {'principal': 7, 'rate_bp': 13, 'months': 12, 'round': 'up'}, {'payment': 1, 'final_payment': -4, 'total_interest': 0}], ['regression: final payment amount, partial-repair probe', {'principal': 1000000, 'rate_bp': 13, 'months': 60, 'round': 'up'}, {'payment': 16722, 'final_payment': 16710, 'total_interest': 3308}], ['control 1', {'principal': 7, 'rate_bp': 1999, 'months': 7, 'round': 'nearest'}, {'payment': 1, 'final_payment': 1, 'total_interest': 0}], ['control 2', {'principal': 30000000, 'rate_bp': 0, 'months': 12, 'round': 'up'}, {'payment': 2500000, 'final_payment': 2500000, 'total_interest': 0}], ['control 3', {'principal': 30000000, 'rate_bp': 600, 'months': 1, 'round': 'up'}, {'payment': 30150000, 'final_payment': 30150000, 'total_interest': 150000}], ['control 4', {'principal': 12345, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 4115, 'final_payment': 4115, 'total_interest': 0}], ['control 5', {'principal': 30000000, 'rate_bp': 1999, 'months': 1, 'round': 'nearest'}, {'payment': 30499750, 'final_payment': 30499750, 'total_interest': 499750}]], [['regression: final payment amount', {'principal': 7, 'rate_bp': 600, 'months': 360, 'round': 'up'}, {'payment': 1, 'final_payment': -876, 'total_interest': -524}], ['control 1', {'principal': 30000000, 'rate_bp': 499, 'months': 2, 'round': 'nearest'}, {'payment': 15093627, 'final_payment': 15093627, 'total_interest': 187254}], ['control 2', {'principal': 999999, 'rate_bp': 0, 'months': 3, 'round': 'nearest'}, {'payment': 333333, 'final_payment': 333333, 'total_interest': 0}], ['control 3', {'principal': 500, 'rate_bp': 0, 'months': 2, 'round': 'up'}, {'payment': 250, 'final_payment': 250, 'total_interest': 0}], ['control 4', {'principal': 2500000, 'rate_bp': 499, 'months': 1, 'round': 'nearest'}, {'payment': 2510396, 'final_payment': 2510396, 'total_interest': 10396}], ['control 5', {'principal': 100000, 'rate_bp': 13, 'months': 1, 'round': 'nearest'}, {'payment': 100011, 'final_payment': 100011, 'total_interest': 11}], ['control 6', {'principal': 100000, 'rate_bp': 0, 'months': 1, 'round': 'up'}, {'payment': 100000, 'final_payment': 100000, 'total_interest': 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)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: final payment amount | {'final_payment': -1123, 'payment': 1, 'total_interest': -771} | {'final_payment': -1123, 'payment': 1, 'total_interest': -771} | Passed |
| control 1 | {'final_payment': 12468, 'payment': 12468, 'total_interest': 123} | {'final_payment': 12468, 'payment': 12468, 'total_interest': 123} | Passed |
| control 2 | {'final_payment': 14573, 'payment': 14573, 'total_interest': 2011} | {'final_payment': 14573, 'payment': 14573, 'total_interest': 2011} | Passed |
| control 3 | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | Passed |
| control 4 | {'final_payment': 250, 'payment': 250, 'total_interest': 0} | {'final_payment': 250, 'payment': 250, 'total_interest': 0} | Passed |
| control 5 | {'final_payment': 504536, 'payment': 504536, 'total_interest': 9072} | {'final_payment': 504536, 'payment': 504536, 'total_interest': 9072} | Passed |
| control 6 | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | {'final_payment': 337369, 'payment': 337369, 'total_interest': 12108} | Passed |
SHA-256 / ce98b8d3e7f10851d113c3f8b19e0ac51b68b87a0df6d93b4ee5eb943de0cce5
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:26.012032+00:00.
Case digest / aa7b83cccc20d2dc31ffaa5323b800ad7e440c4b47ba87a71096e038a7c87c9a