FAILURE MAP
← Case archive

FA-58831 / Loan amortization schedules / Open access

Graduated payment schedule: step count limit · case 01

The schedule re-levels one year early and skips the last step.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The last graduated year is excluded from stepping.

VERIFIED REPAIR

Step for years 1..steps.

Unsuccessful approach: Allowing one extra step pushes the re-level a year late.

Case contract

x = {'principal', 'rate_bp', 'months', 'initial_payment', 'step_bp', 'steps'}. Month m (1-based) is in year t = (m-1)//12. For t < steps+1 the year payment starts at initial_payment and each new year multiplies the previous year payment by (10000+step_bp)/10000, rounded half-up. At the start of year steps+1 (if the loan runs that long) the payment is re-leveled on the balance over the remaining months (exact annuity, half-up) and stays fixed. Interest round_half_up(balance*bp/120000); balance += interest - payment (it may grow). Return {'year_payments', 'peak_balance', 'end_balance'}.

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']
    n = x['months']
    bal = x['principal']
    pay = x['initial_payment']
    years = [pay]
    peak = bal
    for m in range(1, n + 1):
        t = (m - 1) // 12
        if m > 1 and (m - 1) % 12 == 0:
            if t < x['steps']:
                pay = rnd(pay * (10000 + x['step_bp']), 10000)
            elif t == x['steps'] + 1:
                pay = level(bal, n - m + 1)
            years.append(pay)
        interest = rnd(bal * bp, 120000)
        bal += interest - pay
        peak = max(peak, bal)
    return {'year_payments': years, 'peak_balance': peak, 'end_balance': bal}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: step count limit', {'principal': 250000, 'rate_bp': 900, 'months': 60, 'initial_payment': 8000, 'step_bp': 250, 'steps': 1}, {'year_payments': [8000, 8200, 2770, 2770, 2770], 'peak_balance': 250000, 'end_balance': -23}], ['control 1', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 250, 'steps': 3}, {'year_payments': [3000, 3075], 'peak_balance': 250000, 'end_balance': 204568}], ['control 2', {'principal': 250000, 'rate_bp': 900, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 7921, 7921], 'peak_balance': 250000, 'end_balance': 9}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 8607], 'peak_balance': 100000, 'end_balance': -4}], ['control 4', {'principal': 1000000, 'rate_bp': 600, 'months': 36, 'initial_payment': 3000, 'step_bp': 250, 'steps': 0}, {'year_payments': [3000, 45414, 45414], 'peak_balance': 1024671, 'end_balance': -2}], ['control 5', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 500, 'step_bp': 1000, 'steps': 0}, {'year_payments': [500, 8607], 'peak_balance': 100000, 'end_balance': -4}], ['control 6', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 24789, 24789, 24789, 24789], 'peak_balance': 1055512, 'end_balance': -16}]], [['regression: step count limit', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 1}, {'year_payments': [3000, 3300], 'peak_balance': 250000, 'end_balance': 201795}], ['regression: step count limit, partial-repair probe', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 2}, {'year_payments': [500, 513, 526, 52144, 52144], 'peak_balance': 1176523, 'end_balance': 4}], ['control 1', {'principal': 250000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 3000, 'step_bp': 250, 'steps': 2}, {'year_payments': [3000, 3075], 'peak_balance': 250000, 'end_balance': 235565}], ['control 2', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 500, 'step_bp': 1000, 'steps': 3}, {'year_payments': [500, 550], 'peak_balance': 105921, 'end_balance': 105921}], ['control 3', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 3}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 1173203, 'end_balance': 1173203}], ['control 4', {'principal': 250000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 8485, 8485], 'peak_balance': 250000, 'end_balance': -6}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 5006, 5006], 'peak_balance': 106341, 'end_balance': -5}]], [['regression: step count limit', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 3000, 'step_bp': 750, 'steps': 1}, {'year_payments': [3000, 3225, 97511], 'peak_balance': 1115035, 'end_balance': 6}], ['control 1', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 0}, {'year_payments': [3000, 6284], 'peak_balance': 100000, 'end_balance': -2}], ['control 2', {'principal': 250000, 'rate_bp': 1200, 'months': 60, 'initial_payment': 20000, 'step_bp': 250, 'steps': 0}, {'year_payments': [20000, 739, 739, 739, 739], 'peak_balance': 250000, 'end_balance': -10}], ['control 3', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 2}, {'year_payments': [3000, 3225], 'peak_balance': 250000, 'end_balance': 217726}], ['control 4', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 815], 'peak_balance': 100000, 'end_balance': 3}], ['control 5', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 3}, {'year_payments': [3000, 3225], 'peak_balance': 100000, 'end_balance': 33645}], ['control 6', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 0}, {'year_payments': [3000, 19659], 'peak_balance': 250000, 'end_balance': -4}]], [['regression: step count limit', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 2}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 100000, 'end_balance': 1568}], ['regression: step count limit, partial-repair probe', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 1}, {'year_payments': [8000, 8200, 86087], 'peak_balance': 1000000, 'end_balance': 5}], ['control 1', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 20000, 'step_bp': 750, 'steps': 3}, {'year_payments': [20000, 21500], 'peak_balance': 100000, 'end_balance': -422889}], ['control 2', {'principal': 1000000, 'rate_bp': 900, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 27064, 27064, 27064, 27064], 'peak_balance': 1087553, 'end_balance': -13}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'months': 36, 'initial_payment': 500, 'step_bp': 1000, 'steps': 3}, {'year_payments': [500, 550, 605], 'peak_balance': 100000, 'end_balance': 98050}], ['control 4', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 8000, 'step_bp': 1000, 'steps': 0}, {'year_payments': [8000, 22616, 22616, 22616, 22616], 'peak_balance': 1000000, 'end_balance': 0}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 500, 'step_bp': 750, 'steps': 3}, {'year_payments': [500, 538], 'peak_balance': 113004, 'end_balance': 113004}]], [['regression: step count limit', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 20000, 'step_bp': 750, 'steps': 1}, {'year_payments': [20000, 21500, 18254, 18254, 18254], 'peak_balance': 1000000, 'end_balance': -11}], ['control 1', {'principal': 100000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 9448], 'peak_balance': 106341, 'end_balance': 5}], ['control 2', {'principal': 100000, 'rate_bp': 600, 'months': 36, 'initial_payment': 20000, 'step_bp': 750, 'steps': 3}, {'year_payments': [20000, 21500, 23113], 'peak_balance': 100000, 'end_balance': -725097}], ['control 3', {'principal': 250000, 'rate_bp': 600, 'months': 60, 'initial_payment': 3000, 'step_bp': 250, 'steps': 0}, {'year_payments': [3000, 5364, 5364, 5364, 5364], 'peak_balance': 250000, 'end_balance': 13}], ['control 4', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 23367], 'peak_balance': 267199, 'end_balance': 0}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 3}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 100000, 'end_balance': 1568}], ['control 6', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 15163], 'peak_balance': 250000, 'end_balance': 4}]]]
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 fixtureActualExpectedOutcome
regression: step count limit{'end_balance': 6, 'peak_balance': 250000, 'year_payments': [8000, 8000, 2849, 2849, 2849]}{'end_balance': -23, 'peak_balance': 250000, 'year_payments': [8000, 8200, 2770, 2770, 2770]}Failed
control 1{'end_balance': 204568, 'peak_balance': 250000, 'year_payments': [3000, 3075]}{'end_balance': 204568, 'peak_balance': 250000, 'year_payments': [3000, 3075]}Passed
control 2{'end_balance': 9, 'peak_balance': 250000, 'year_payments': [8000, 7921, 7921]}{'end_balance': 9, 'peak_balance': 250000, 'year_payments': [8000, 7921, 7921]}Passed
control 3{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}Passed
control 4{'end_balance': -2, 'peak_balance': 1024671, 'year_payments': [3000, 45414, 45414]}{'end_balance': -2, 'peak_balance': 1024671, 'year_payments': [3000, 45414, 45414]}Passed
control 5{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}Passed
control 6{'end_balance': -16, 'peak_balance': 1055512, 'year_payments': [500, 24789, 24789, 24789, 24789]}{'end_balance': -16, 'peak_balance': 1055512, 'year_payments': [500, 24789, 24789, 24789, 24789]}Passed

SHA-256 / c39f976c0a462df6889af1a6b62356bd83b0eadca5209879cf39310f09dea311

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']
    n = x['months']
    bal = x['principal']
    pay = x['initial_payment']
    years = [pay]
    peak = bal
    for m in range(1, n + 1):
        t = (m - 1) // 12
        if m > 1 and (m - 1) % 12 == 0:
            if t <= x['steps'] + 1:
                pay = rnd(pay * (10000 + x['step_bp']), 10000)
            elif t == x['steps'] + 1:
                pay = level(bal, n - m + 1)
            years.append(pay)
        interest = rnd(bal * bp, 120000)
        bal += interest - pay
        peak = max(peak, bal)
    return {'year_payments': years, 'peak_balance': peak, 'end_balance': bal}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: step count limit', {'principal': 250000, 'rate_bp': 900, 'months': 60, 'initial_payment': 8000, 'step_bp': 250, 'steps': 1}, {'year_payments': [8000, 8200, 2770, 2770, 2770], 'peak_balance': 250000, 'end_balance': -23}], ['control 1', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 250, 'steps': 3}, {'year_payments': [3000, 3075], 'peak_balance': 250000, 'end_balance': 204568}], ['control 2', {'principal': 250000, 'rate_bp': 900, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 7921, 7921], 'peak_balance': 250000, 'end_balance': 9}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 8607], 'peak_balance': 100000, 'end_balance': -4}], ['control 4', {'principal': 1000000, 'rate_bp': 600, 'months': 36, 'initial_payment': 3000, 'step_bp': 250, 'steps': 0}, {'year_payments': [3000, 45414, 45414], 'peak_balance': 1024671, 'end_balance': -2}], ['control 5', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 500, 'step_bp': 1000, 'steps': 0}, {'year_payments': [500, 8607], 'peak_balance': 100000, 'end_balance': -4}], ['control 6', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 24789, 24789, 24789, 24789], 'peak_balance': 1055512, 'end_balance': -16}]], [['regression: step count limit', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 1}, {'year_payments': [3000, 3300], 'peak_balance': 250000, 'end_balance': 201795}], ['regression: step count limit, partial-repair probe', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 2}, {'year_payments': [500, 513, 526, 52144, 52144], 'peak_balance': 1176523, 'end_balance': 4}], ['control 1', {'principal': 250000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 3000, 'step_bp': 250, 'steps': 2}, {'year_payments': [3000, 3075], 'peak_balance': 250000, 'end_balance': 235565}], ['control 2', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 500, 'step_bp': 1000, 'steps': 3}, {'year_payments': [500, 550], 'peak_balance': 105921, 'end_balance': 105921}], ['control 3', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 3}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 1173203, 'end_balance': 1173203}], ['control 4', {'principal': 250000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 8485, 8485], 'peak_balance': 250000, 'end_balance': -6}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 5006, 5006], 'peak_balance': 106341, 'end_balance': -5}]], [['regression: step count limit', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 3000, 'step_bp': 750, 'steps': 1}, {'year_payments': [3000, 3225, 97511], 'peak_balance': 1115035, 'end_balance': 6}], ['control 1', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 0}, {'year_payments': [3000, 6284], 'peak_balance': 100000, 'end_balance': -2}], ['control 2', {'principal': 250000, 'rate_bp': 1200, 'months': 60, 'initial_payment': 20000, 'step_bp': 250, 'steps': 0}, {'year_payments': [20000, 739, 739, 739, 739], 'peak_balance': 250000, 'end_balance': -10}], ['control 3', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 2}, {'year_payments': [3000, 3225], 'peak_balance': 250000, 'end_balance': 217726}], ['control 4', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 815], 'peak_balance': 100000, 'end_balance': 3}], ['control 5', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 3}, {'year_payments': [3000, 3225], 'peak_balance': 100000, 'end_balance': 33645}], ['control 6', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 0}, {'year_payments': [3000, 19659], 'peak_balance': 250000, 'end_balance': -4}]], [['regression: step count limit', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 2}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 100000, 'end_balance': 1568}], ['regression: step count limit, partial-repair probe', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 1}, {'year_payments': [8000, 8200, 86087], 'peak_balance': 1000000, 'end_balance': 5}], ['control 1', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 20000, 'step_bp': 750, 'steps': 3}, {'year_payments': [20000, 21500], 'peak_balance': 100000, 'end_balance': -422889}], ['control 2', {'principal': 1000000, 'rate_bp': 900, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 27064, 27064, 27064, 27064], 'peak_balance': 1087553, 'end_balance': -13}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'months': 36, 'initial_payment': 500, 'step_bp': 1000, 'steps': 3}, {'year_payments': [500, 550, 605], 'peak_balance': 100000, 'end_balance': 98050}], ['control 4', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 8000, 'step_bp': 1000, 'steps': 0}, {'year_payments': [8000, 22616, 22616, 22616, 22616], 'peak_balance': 1000000, 'end_balance': 0}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 500, 'step_bp': 750, 'steps': 3}, {'year_payments': [500, 538], 'peak_balance': 113004, 'end_balance': 113004}]], [['regression: step count limit', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 20000, 'step_bp': 750, 'steps': 1}, {'year_payments': [20000, 21500, 18254, 18254, 18254], 'peak_balance': 1000000, 'end_balance': -11}], ['control 1', {'principal': 100000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 9448], 'peak_balance': 106341, 'end_balance': 5}], ['control 2', {'principal': 100000, 'rate_bp': 600, 'months': 36, 'initial_payment': 20000, 'step_bp': 750, 'steps': 3}, {'year_payments': [20000, 21500, 23113], 'peak_balance': 100000, 'end_balance': -725097}], ['control 3', {'principal': 250000, 'rate_bp': 600, 'months': 60, 'initial_payment': 3000, 'step_bp': 250, 'steps': 0}, {'year_payments': [3000, 5364, 5364, 5364, 5364], 'peak_balance': 250000, 'end_balance': 13}], ['control 4', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 23367], 'peak_balance': 267199, 'end_balance': 0}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 3}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 100000, 'end_balance': 1568}], ['control 6', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 15163], 'peak_balance': 250000, 'end_balance': 4}]]]
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 fixtureActualExpectedOutcome
regression: step count limit{'end_balance': -231917, 'peak_balance': 250000, 'year_payments': [8000, 8200, 8405, 8405, 8405]}{'end_balance': -23, 'peak_balance': 250000, 'year_payments': [8000, 8200, 2770, 2770, 2770]}Failed
control 1{'end_balance': 204568, 'peak_balance': 250000, 'year_payments': [3000, 3075]}{'end_balance': 204568, 'peak_balance': 250000, 'year_payments': [3000, 3075]}Passed
control 2{'end_balance': -7299, 'peak_balance': 250000, 'year_payments': [8000, 8200, 8200]}{'end_balance': 9, 'peak_balance': 250000, 'year_payments': [8000, 7921, 7921]}Failed
control 3{'end_balance': 99840, 'peak_balance': 100000, 'year_payments': [500, 513]}{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}Failed
control 4{'end_balance': 1076767, 'peak_balance': 1076767, 'year_payments': [3000, 3075, 3075]}{'end_balance': -2, 'peak_balance': 1024671, 'year_payments': [3000, 45414, 45414]}Failed
control 5{'end_balance': 99383, 'peak_balance': 100000, 'year_payments': [500, 550]}{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}Failed
control 6{'end_balance': 1313263, 'peak_balance': 1313263, 'year_payments': [500, 513, 513, 513, 513]}{'end_balance': -16, 'peak_balance': 1055512, 'year_payments': [500, 24789, 24789, 24789, 24789]}Failed

SHA-256 / a4db6a6ee631418ff12e3e6f3f88c74360736ffd255cfe30faa9560e949ed47e

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']
    n = x['months']
    bal = x['principal']
    pay = x['initial_payment']
    years = [pay]
    peak = bal
    for m in range(1, n + 1):
        t = (m - 1) // 12
        if m > 1 and (m - 1) % 12 == 0:
            if t <= x['steps']:
                pay = rnd(pay * (10000 + x['step_bp']), 10000)
            elif t == x['steps'] + 1:
                pay = level(bal, n - m + 1)
            years.append(pay)
        interest = rnd(bal * bp, 120000)
        bal += interest - pay
        peak = max(peak, bal)
    return {'year_payments': years, 'peak_balance': peak, 'end_balance': bal}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: step count limit', {'principal': 250000, 'rate_bp': 900, 'months': 60, 'initial_payment': 8000, 'step_bp': 250, 'steps': 1}, {'year_payments': [8000, 8200, 2770, 2770, 2770], 'peak_balance': 250000, 'end_balance': -23}], ['control 1', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 250, 'steps': 3}, {'year_payments': [3000, 3075], 'peak_balance': 250000, 'end_balance': 204568}], ['control 2', {'principal': 250000, 'rate_bp': 900, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 7921, 7921], 'peak_balance': 250000, 'end_balance': 9}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 8607], 'peak_balance': 100000, 'end_balance': -4}], ['control 4', {'principal': 1000000, 'rate_bp': 600, 'months': 36, 'initial_payment': 3000, 'step_bp': 250, 'steps': 0}, {'year_payments': [3000, 45414, 45414], 'peak_balance': 1024671, 'end_balance': -2}], ['control 5', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 500, 'step_bp': 1000, 'steps': 0}, {'year_payments': [500, 8607], 'peak_balance': 100000, 'end_balance': -4}], ['control 6', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 24789, 24789, 24789, 24789], 'peak_balance': 1055512, 'end_balance': -16}]], [['regression: step count limit', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 1}, {'year_payments': [3000, 3300], 'peak_balance': 250000, 'end_balance': 201795}], ['regression: step count limit, partial-repair probe', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 2}, {'year_payments': [500, 513, 526, 52144, 52144], 'peak_balance': 1176523, 'end_balance': 4}], ['control 1', {'principal': 250000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 3000, 'step_bp': 250, 'steps': 2}, {'year_payments': [3000, 3075], 'peak_balance': 250000, 'end_balance': 235565}], ['control 2', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 500, 'step_bp': 1000, 'steps': 3}, {'year_payments': [500, 550], 'peak_balance': 105921, 'end_balance': 105921}], ['control 3', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 3}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 1173203, 'end_balance': 1173203}], ['control 4', {'principal': 250000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 8485, 8485], 'peak_balance': 250000, 'end_balance': -6}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 5006, 5006], 'peak_balance': 106341, 'end_balance': -5}]], [['regression: step count limit', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 3000, 'step_bp': 750, 'steps': 1}, {'year_payments': [3000, 3225, 97511], 'peak_balance': 1115035, 'end_balance': 6}], ['control 1', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 0}, {'year_payments': [3000, 6284], 'peak_balance': 100000, 'end_balance': -2}], ['control 2', {'principal': 250000, 'rate_bp': 1200, 'months': 60, 'initial_payment': 20000, 'step_bp': 250, 'steps': 0}, {'year_payments': [20000, 739, 739, 739, 739], 'peak_balance': 250000, 'end_balance': -10}], ['control 3', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 2}, {'year_payments': [3000, 3225], 'peak_balance': 250000, 'end_balance': 217726}], ['control 4', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 815], 'peak_balance': 100000, 'end_balance': 3}], ['control 5', {'principal': 100000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 750, 'steps': 3}, {'year_payments': [3000, 3225], 'peak_balance': 100000, 'end_balance': 33645}], ['control 6', {'principal': 250000, 'rate_bp': 600, 'months': 24, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 0}, {'year_payments': [3000, 19659], 'peak_balance': 250000, 'end_balance': -4}]], [['regression: step count limit', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 2}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 100000, 'end_balance': 1568}], ['regression: step count limit, partial-repair probe', {'principal': 1000000, 'rate_bp': 900, 'months': 36, 'initial_payment': 8000, 'step_bp': 250, 'steps': 1}, {'year_payments': [8000, 8200, 86087], 'peak_balance': 1000000, 'end_balance': 5}], ['control 1', {'principal': 100000, 'rate_bp': 900, 'months': 24, 'initial_payment': 20000, 'step_bp': 750, 'steps': 3}, {'year_payments': [20000, 21500], 'peak_balance': 100000, 'end_balance': -422889}], ['control 2', {'principal': 1000000, 'rate_bp': 900, 'months': 60, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 27064, 27064, 27064, 27064], 'peak_balance': 1087553, 'end_balance': -13}], ['control 3', {'principal': 100000, 'rate_bp': 600, 'months': 36, 'initial_payment': 500, 'step_bp': 1000, 'steps': 3}, {'year_payments': [500, 550, 605], 'peak_balance': 100000, 'end_balance': 98050}], ['control 4', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 8000, 'step_bp': 1000, 'steps': 0}, {'year_payments': [8000, 22616, 22616, 22616, 22616], 'peak_balance': 1000000, 'end_balance': 0}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 500, 'step_bp': 750, 'steps': 3}, {'year_payments': [500, 538], 'peak_balance': 113004, 'end_balance': 113004}]], [['regression: step count limit', {'principal': 1000000, 'rate_bp': 600, 'months': 60, 'initial_payment': 20000, 'step_bp': 750, 'steps': 1}, {'year_payments': [20000, 21500, 18254, 18254, 18254], 'peak_balance': 1000000, 'end_balance': -11}], ['control 1', {'principal': 100000, 'rate_bp': 1200, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 9448], 'peak_balance': 106341, 'end_balance': 5}], ['control 2', {'principal': 100000, 'rate_bp': 600, 'months': 36, 'initial_payment': 20000, 'step_bp': 750, 'steps': 3}, {'year_payments': [20000, 21500, 23113], 'peak_balance': 100000, 'end_balance': -725097}], ['control 3', {'principal': 250000, 'rate_bp': 600, 'months': 60, 'initial_payment': 3000, 'step_bp': 250, 'steps': 0}, {'year_payments': [3000, 5364, 5364, 5364, 5364], 'peak_balance': 250000, 'end_balance': 13}], ['control 4', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 500, 'step_bp': 250, 'steps': 0}, {'year_payments': [500, 23367], 'peak_balance': 267199, 'end_balance': 0}], ['control 5', {'principal': 100000, 'rate_bp': 1200, 'months': 36, 'initial_payment': 3000, 'step_bp': 1000, 'steps': 3}, {'year_payments': [3000, 3300, 3630], 'peak_balance': 100000, 'end_balance': 1568}], ['control 6', {'principal': 250000, 'rate_bp': 900, 'months': 24, 'initial_payment': 8000, 'step_bp': 250, 'steps': 0}, {'year_payments': [8000, 15163], 'peak_balance': 250000, 'end_balance': 4}]]]
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 fixtureActualExpectedOutcome
regression: step count limit{'end_balance': -23, 'peak_balance': 250000, 'year_payments': [8000, 8200, 2770, 2770, 2770]}{'end_balance': -23, 'peak_balance': 250000, 'year_payments': [8000, 8200, 2770, 2770, 2770]}Passed
control 1{'end_balance': 204568, 'peak_balance': 250000, 'year_payments': [3000, 3075]}{'end_balance': 204568, 'peak_balance': 250000, 'year_payments': [3000, 3075]}Passed
control 2{'end_balance': 9, 'peak_balance': 250000, 'year_payments': [8000, 7921, 7921]}{'end_balance': 9, 'peak_balance': 250000, 'year_payments': [8000, 7921, 7921]}Passed
control 3{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}Passed
control 4{'end_balance': -2, 'peak_balance': 1024671, 'year_payments': [3000, 45414, 45414]}{'end_balance': -2, 'peak_balance': 1024671, 'year_payments': [3000, 45414, 45414]}Passed
control 5{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}{'end_balance': -4, 'peak_balance': 100000, 'year_payments': [500, 8607]}Passed
control 6{'end_balance': -16, 'peak_balance': 1055512, 'year_payments': [500, 24789, 24789, 24789, 24789]}{'end_balance': -16, 'peak_balance': 1055512, 'year_payments': [500, 24789, 24789, 24789, 24789]}Passed

SHA-256 / ec383b795f43c7a488dc5ba8e00fcefba574b5fad42a943b0cea331eac98c3ff

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:30.461163+00:00.

Case digest / 6d058a3f3f4075298c85d73ebcfcd3bbdcc90a5cb3829221d71428e40b179f80