FA-63446 / Actuarial life tables / Open access
Commutation-function life annuities: Temporary annuities stop one payment early · case 01
An n-year annuity-due makes n-1 payments.
ROOT CAUSE
The ending commutation index is age+n-1.
VERIFIED REPAIR
End at age+n.
Unsuccessful approach: Ending at age+n+1 pays one extra year.
Case contract
Input l by age from 0, i (per mille), age, n (None = whole life). v=1/(1+i); D_k = v^k l_k (zero beyond the table); N_k = sum of D from k. end = table length for whole life else min(length, age+n). Annuity-due = (N_age - N_end)/D_age; immediate = (N_{age+1} - N_{end+1})/D_age. Missing or extinct age -> 'invalid age'. Return both rounded to 6.
Why this case matters
Life-table arithmetic compounds across ages, so one misplaced index or assumption shifts every downstream value.
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):
l=x['l']; v=1/(1+Fraction(x['i'],1000)); a=x['age']; n=x['n']
if a<0 or a>=len(l) or l[a]==0: return 'invalid age'
D=[v**k*l[k] for k in range(len(l))]+[Fraction(0)]*2
N=[sum(D[k:]) for k in range(len(D))]
end=len(l) if n is None else min(len(l),a+n-1)
due=(N[a]-N[end])/D[a]
imm=(N[a+1]-N[end+1])/D[a]
return [round(float(due),6),round(float(imm),6)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['temporary annuity 0', {'l': [100000, 99642, 99195, 98659, 98058, 97356, 96541, 95648], 'i': 40, 'age': 2, 'n': 4}, [3.742817, 3.57475]], ['temporary annuity 1', {'l': [100000, 99417, 98755, 97991, 97132, 96168, 95076, 93884], 'i': 40, 'age': 3, 'n': 4}, [3.723016, 3.541994]], ['temporary annuity 2', {'l': [100000, 99453, 98834, 98150, 97362, 96453, 95404, 94237, 92936, 91494], 'i': 30, 'age': 1, 'n': 4}, [3.790978, 3.652664]], ['whole life open table', {'l': [100000, 99787, 99485, 99137, 98692, 98173, 97574, 96876, 96089], 'i': 40, 'age': 2, 'n': None}, [6.154727, 5.154727]], ['whole life closed table', {'l': [100000, 99429, 98772, 98032, 97167, 96144, 95012, 0], 'i': 35, 'age': 1, 'n': None}, [5.408838, 4.408838]], ['term beyond table', {'l': [100000, 99641, 99192, 98692, 98130, 97510], 'i': 45, 'age': 3, 'n': 10}, [2.856251, 1.856251]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99524, 98997, 98400, 97704, 96904], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938906]]], [['temporary annuity 0', {'l': [100000, 99775, 99489, 99167, 98767, 98288, 97747], 'i': 50, 'age': 0, 'n': 4}, [3.709274, 3.521833]], ['temporary annuity 1', {'l': [100000, 99694, 99327, 98881, 98358, 97745, 97043], 'i': 50, 'age': 2, 'n': 3}, [2.846285, 2.696364]], ['temporary annuity 2', {'l': [100000, 99598, 99130, 98569, 97893, 97088, 96178, 95100], 'i': 30, 'age': 3, 'n': 3}, [2.892649, 2.785592]], ['whole life open table', {'l': [100000, 99755, 99463, 99139, 98746, 98320, 97809, 97211, 96498], 'i': 40, 'age': 2, 'n': None}, [6.16574, 5.16574]], ['whole life closed table', {'l': [100000, 99581, 99117, 98592, 97955, 97267, 96482, 0], 'i': 35, 'age': 1, 'n': None}, [5.440099, 4.440099]], ['term beyond table', {'l': [100000, 99736, 99406, 99010, 98571, 98012], 'i': 45, 'age': 3, 'n': 10}, [2.859194, 1.859194]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99652, 99228, 98711, 98105, 97406], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.940113]]], [['temporary annuity 0', {'l': [100000, 99420, 98725, 97957, 97073, 96081, 94960, 93711], 'i': 30, 'age': 3, 'n': 2}, [1.962112, 1.886656]], ['temporary annuity 1', {'l': [100000, 99638, 99204, 98701, 98137, 97506, 96775, 95931], 'i': 40, 'age': 2, 'n': 4}, [3.745055, 3.57893]], ['temporary annuity 2', {'l': [100000, 99657, 99275, 98813, 98300, 97719, 97018], 'i': 40, 'age': 2, 'n': 2}, [1.957064, 1.87254]], ['whole life open table', {'l': [100000, 99786, 99507, 99161, 98768, 98291, 97735, 97082, 96357], 'i': 40, 'age': 2, 'n': None}, [6.160792, 5.160792]], ['whole life closed table', {'l': [100000, 99431, 98736, 97957, 97098, 96120, 95028, 0], 'i': 35, 'age': 1, 'n': None}, [5.406995, 4.406995]], ['term beyond table', {'l': [100000, 99738, 99412, 99051, 98642, 98145], 'i': 45, 'age': 3, 'n': 10}, [2.86034, 1.86034]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99469, 98882, 98185, 97345, 96416], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938387]]], [['temporary annuity 0', {'l': [100000, 99534, 99007, 98399, 97724, 96918, 95991, 94948, 93777], 'i': 30, 'age': 1, 'n': 2}, [1.965733, 1.897581]], ['temporary annuity 1', {'l': [100000, 99712, 99416, 99061, 98637, 98130, 97513, 96832, 96053], 'i': 30, 'age': 0, 'n': 2}, [1.968078, 1.905169]], ['temporary annuity 2', {'l': [100000, 99756, 99437, 99029, 98581, 98058, 97481, 96805, 96011, 95126, 94098], 'i': 30, 'age': 2, 'n': 3}, [2.901372, 2.803822]], ['whole life open table', {'l': [100000, 99723, 99381, 98995, 98553, 98028, 97454, 96770, 95995], 'i': 40, 'age': 2, 'n': None}, [6.153501, 5.153501]], ['whole life closed table', {'l': [100000, 99428, 98812, 98089, 97289, 96384, 95343, 0], 'i': 35, 'age': 1, 'n': None}, [5.41582, 4.41582]], ['term beyond table', {'l': [100000, 99661, 99257, 98733, 98143, 97444], 'i': 45, 'age': 3, 'n': 10}, [2.854994, 1.854994]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99448, 98803, 98055, 97195, 96207], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938189]]], [['temporary annuity 0', {'l': [100000, 99726, 99420, 99062, 98618, 98121, 97557, 96898, 96138], 'i': 50, 'age': 0, 'n': 2}, [1.949771, 1.85154]], ['temporary annuity 1', {'l': [100000, 99470, 98858, 98184, 97426, 96591, 95638, 94558], 'i': 30, 'age': 3, 'n': 3}, [2.890681, 2.782092]], ['temporary annuity 2', {'l': [100000, 99476, 98844, 98126, 97312, 96401, 95355, 94159, 92804], 'i': 50, 'age': 1, 'n': 2}, [1.94633, 1.84105]], ['whole life open table', {'l': [100000, 99581, 99109, 98575, 97949, 97206, 96380, 95454, 94396], 'i': 40, 'age': 2, 'n': None}, [6.117634, 5.117634]], ['whole life closed table', {'l': [100000, 99415, 98764, 98017, 97154, 96172, 95049, 0], 'i': 35, 'age': 1, 'n': None}, [5.409681, 4.409681]], ['term beyond table', {'l': [100000, 99737, 99444, 99071, 98636, 98121], 'i': 45, 'age': 3, 'n': 10}, [2.859685, 1.859685]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99758, 99438, 99084, 98670, 98174], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.941113]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), 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 |
|---|---|---|---|
| temporary annuity 0 | [2.870301, 2.742817] | [3.742817, 3.57475] | Failed |
| temporary annuity 1 | [2.860466, 2.723016] | [3.723016, 3.541994] | Failed |
| temporary annuity 2 | [2.895077, 2.790978] | [3.790978, 3.652664] | Failed |
| whole life open table | [6.154727, 5.154727] | [6.154727, 5.154727] | Passed |
| whole life closed table | [5.408838, 4.408838] | [5.408838, 4.408838] | Passed |
| term beyond table | [2.856251, 1.856251] | [2.856251, 1.856251] | Passed |
| extinct age rejected | invalid age | invalid age | Passed |
| one-year term | [0.0, 0.0] | [1.0, 0.938906] | Failed |
SHA-256 / 60210cf5d0053d5d985ec22c9d806f62cdc52763539c4c475df1435dcdfde938
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):
l=x['l']; v=1/(1+Fraction(x['i'],1000)); a=x['age']; n=x['n']
if a<0 or a>=len(l) or l[a]==0: return 'invalid age'
D=[v**k*l[k] for k in range(len(l))]+[Fraction(0)]*2
N=[sum(D[k:]) for k in range(len(D))]
end=len(l) if n is None else min(len(l),a+n+1)
due=(N[a]-N[end])/D[a]
imm=(N[a+1]-N[end+1])/D[a]
return [round(float(due),6),round(float(imm),6)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['temporary annuity 0', {'l': [100000, 99642, 99195, 98659, 98058, 97356, 96541, 95648], 'i': 40, 'age': 2, 'n': 4}, [3.742817, 3.57475]], ['temporary annuity 1', {'l': [100000, 99417, 98755, 97991, 97132, 96168, 95076, 93884], 'i': 40, 'age': 3, 'n': 4}, [3.723016, 3.541994]], ['temporary annuity 2', {'l': [100000, 99453, 98834, 98150, 97362, 96453, 95404, 94237, 92936, 91494], 'i': 30, 'age': 1, 'n': 4}, [3.790978, 3.652664]], ['whole life open table', {'l': [100000, 99787, 99485, 99137, 98692, 98173, 97574, 96876, 96089], 'i': 40, 'age': 2, 'n': None}, [6.154727, 5.154727]], ['whole life closed table', {'l': [100000, 99429, 98772, 98032, 97167, 96144, 95012, 0], 'i': 35, 'age': 1, 'n': None}, [5.408838, 4.408838]], ['term beyond table', {'l': [100000, 99641, 99192, 98692, 98130, 97510], 'i': 45, 'age': 3, 'n': 10}, [2.856251, 1.856251]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99524, 98997, 98400, 97704, 96904], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938906]]], [['temporary annuity 0', {'l': [100000, 99775, 99489, 99167, 98767, 98288, 97747], 'i': 50, 'age': 0, 'n': 4}, [3.709274, 3.521833]], ['temporary annuity 1', {'l': [100000, 99694, 99327, 98881, 98358, 97745, 97043], 'i': 50, 'age': 2, 'n': 3}, [2.846285, 2.696364]], ['temporary annuity 2', {'l': [100000, 99598, 99130, 98569, 97893, 97088, 96178, 95100], 'i': 30, 'age': 3, 'n': 3}, [2.892649, 2.785592]], ['whole life open table', {'l': [100000, 99755, 99463, 99139, 98746, 98320, 97809, 97211, 96498], 'i': 40, 'age': 2, 'n': None}, [6.16574, 5.16574]], ['whole life closed table', {'l': [100000, 99581, 99117, 98592, 97955, 97267, 96482, 0], 'i': 35, 'age': 1, 'n': None}, [5.440099, 4.440099]], ['term beyond table', {'l': [100000, 99736, 99406, 99010, 98571, 98012], 'i': 45, 'age': 3, 'n': 10}, [2.859194, 1.859194]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99652, 99228, 98711, 98105, 97406], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.940113]]], [['temporary annuity 0', {'l': [100000, 99420, 98725, 97957, 97073, 96081, 94960, 93711], 'i': 30, 'age': 3, 'n': 2}, [1.962112, 1.886656]], ['temporary annuity 1', {'l': [100000, 99638, 99204, 98701, 98137, 97506, 96775, 95931], 'i': 40, 'age': 2, 'n': 4}, [3.745055, 3.57893]], ['temporary annuity 2', {'l': [100000, 99657, 99275, 98813, 98300, 97719, 97018], 'i': 40, 'age': 2, 'n': 2}, [1.957064, 1.87254]], ['whole life open table', {'l': [100000, 99786, 99507, 99161, 98768, 98291, 97735, 97082, 96357], 'i': 40, 'age': 2, 'n': None}, [6.160792, 5.160792]], ['whole life closed table', {'l': [100000, 99431, 98736, 97957, 97098, 96120, 95028, 0], 'i': 35, 'age': 1, 'n': None}, [5.406995, 4.406995]], ['term beyond table', {'l': [100000, 99738, 99412, 99051, 98642, 98145], 'i': 45, 'age': 3, 'n': 10}, [2.86034, 1.86034]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99469, 98882, 98185, 97345, 96416], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938387]]], [['temporary annuity 0', {'l': [100000, 99534, 99007, 98399, 97724, 96918, 95991, 94948, 93777], 'i': 30, 'age': 1, 'n': 2}, [1.965733, 1.897581]], ['temporary annuity 1', {'l': [100000, 99712, 99416, 99061, 98637, 98130, 97513, 96832, 96053], 'i': 30, 'age': 0, 'n': 2}, [1.968078, 1.905169]], ['temporary annuity 2', {'l': [100000, 99756, 99437, 99029, 98581, 98058, 97481, 96805, 96011, 95126, 94098], 'i': 30, 'age': 2, 'n': 3}, [2.901372, 2.803822]], ['whole life open table', {'l': [100000, 99723, 99381, 98995, 98553, 98028, 97454, 96770, 95995], 'i': 40, 'age': 2, 'n': None}, [6.153501, 5.153501]], ['whole life closed table', {'l': [100000, 99428, 98812, 98089, 97289, 96384, 95343, 0], 'i': 35, 'age': 1, 'n': None}, [5.41582, 4.41582]], ['term beyond table', {'l': [100000, 99661, 99257, 98733, 98143, 97444], 'i': 45, 'age': 3, 'n': 10}, [2.854994, 1.854994]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99448, 98803, 98055, 97195, 96207], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938189]]], [['temporary annuity 0', {'l': [100000, 99726, 99420, 99062, 98618, 98121, 97557, 96898, 96138], 'i': 50, 'age': 0, 'n': 2}, [1.949771, 1.85154]], ['temporary annuity 1', {'l': [100000, 99470, 98858, 98184, 97426, 96591, 95638, 94558], 'i': 30, 'age': 3, 'n': 3}, [2.890681, 2.782092]], ['temporary annuity 2', {'l': [100000, 99476, 98844, 98126, 97312, 96401, 95355, 94159, 92804], 'i': 50, 'age': 1, 'n': 2}, [1.94633, 1.84105]], ['whole life open table', {'l': [100000, 99581, 99109, 98575, 97949, 97206, 96380, 95454, 94396], 'i': 40, 'age': 2, 'n': None}, [6.117634, 5.117634]], ['whole life closed table', {'l': [100000, 99415, 98764, 98017, 97154, 96172, 95049, 0], 'i': 35, 'age': 1, 'n': None}, [5.409681, 4.409681]], ['term beyond table', {'l': [100000, 99737, 99444, 99071, 98636, 98121], 'i': 45, 'age': 3, 'n': 10}, [2.859685, 1.859685]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99758, 99438, 99084, 98670, 98174], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.941113]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), 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 |
|---|---|---|---|
| temporary annuity 0 | [4.57475, 4.367287] | [3.742817, 3.57475] | Failed |
| temporary annuity 1 | [4.541994, 3.541994] | [3.723016, 3.541994] | Failed |
| temporary annuity 2 | [4.652664, 4.480154] | [3.790978, 3.652664] | Failed |
| whole life open table | [6.154727, 5.154727] | [6.154727, 5.154727] | Passed |
| whole life closed table | [5.408838, 4.408838] | [5.408838, 4.408838] | Passed |
| term beyond table | [2.856251, 1.856251] | [2.856251, 1.856251] | Passed |
| extinct age rejected | invalid age | invalid age | Passed |
| one-year term | [1.938906, 1.819975] | [1.0, 0.938906] | Failed |
SHA-256 / c84eda41bc809c47381d4cb52935a8d1a797807e69396fbf99517535679bb1d3
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):
l=x['l']; v=1/(1+Fraction(x['i'],1000)); a=x['age']; n=x['n']
if a<0 or a>=len(l) or l[a]==0: return 'invalid age'
D=[v**k*l[k] for k in range(len(l))]+[Fraction(0)]*2
N=[sum(D[k:]) for k in range(len(D))]
end=len(l) if n is None else min(len(l),a+n)
due=(N[a]-N[end])/D[a]
imm=(N[a+1]-N[end+1])/D[a]
return [round(float(due),6),round(float(imm),6)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['temporary annuity 0', {'l': [100000, 99642, 99195, 98659, 98058, 97356, 96541, 95648], 'i': 40, 'age': 2, 'n': 4}, [3.742817, 3.57475]], ['temporary annuity 1', {'l': [100000, 99417, 98755, 97991, 97132, 96168, 95076, 93884], 'i': 40, 'age': 3, 'n': 4}, [3.723016, 3.541994]], ['temporary annuity 2', {'l': [100000, 99453, 98834, 98150, 97362, 96453, 95404, 94237, 92936, 91494], 'i': 30, 'age': 1, 'n': 4}, [3.790978, 3.652664]], ['whole life open table', {'l': [100000, 99787, 99485, 99137, 98692, 98173, 97574, 96876, 96089], 'i': 40, 'age': 2, 'n': None}, [6.154727, 5.154727]], ['whole life closed table', {'l': [100000, 99429, 98772, 98032, 97167, 96144, 95012, 0], 'i': 35, 'age': 1, 'n': None}, [5.408838, 4.408838]], ['term beyond table', {'l': [100000, 99641, 99192, 98692, 98130, 97510], 'i': 45, 'age': 3, 'n': 10}, [2.856251, 1.856251]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99524, 98997, 98400, 97704, 96904], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938906]]], [['temporary annuity 0', {'l': [100000, 99775, 99489, 99167, 98767, 98288, 97747], 'i': 50, 'age': 0, 'n': 4}, [3.709274, 3.521833]], ['temporary annuity 1', {'l': [100000, 99694, 99327, 98881, 98358, 97745, 97043], 'i': 50, 'age': 2, 'n': 3}, [2.846285, 2.696364]], ['temporary annuity 2', {'l': [100000, 99598, 99130, 98569, 97893, 97088, 96178, 95100], 'i': 30, 'age': 3, 'n': 3}, [2.892649, 2.785592]], ['whole life open table', {'l': [100000, 99755, 99463, 99139, 98746, 98320, 97809, 97211, 96498], 'i': 40, 'age': 2, 'n': None}, [6.16574, 5.16574]], ['whole life closed table', {'l': [100000, 99581, 99117, 98592, 97955, 97267, 96482, 0], 'i': 35, 'age': 1, 'n': None}, [5.440099, 4.440099]], ['term beyond table', {'l': [100000, 99736, 99406, 99010, 98571, 98012], 'i': 45, 'age': 3, 'n': 10}, [2.859194, 1.859194]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99652, 99228, 98711, 98105, 97406], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.940113]]], [['temporary annuity 0', {'l': [100000, 99420, 98725, 97957, 97073, 96081, 94960, 93711], 'i': 30, 'age': 3, 'n': 2}, [1.962112, 1.886656]], ['temporary annuity 1', {'l': [100000, 99638, 99204, 98701, 98137, 97506, 96775, 95931], 'i': 40, 'age': 2, 'n': 4}, [3.745055, 3.57893]], ['temporary annuity 2', {'l': [100000, 99657, 99275, 98813, 98300, 97719, 97018], 'i': 40, 'age': 2, 'n': 2}, [1.957064, 1.87254]], ['whole life open table', {'l': [100000, 99786, 99507, 99161, 98768, 98291, 97735, 97082, 96357], 'i': 40, 'age': 2, 'n': None}, [6.160792, 5.160792]], ['whole life closed table', {'l': [100000, 99431, 98736, 97957, 97098, 96120, 95028, 0], 'i': 35, 'age': 1, 'n': None}, [5.406995, 4.406995]], ['term beyond table', {'l': [100000, 99738, 99412, 99051, 98642, 98145], 'i': 45, 'age': 3, 'n': 10}, [2.86034, 1.86034]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99469, 98882, 98185, 97345, 96416], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938387]]], [['temporary annuity 0', {'l': [100000, 99534, 99007, 98399, 97724, 96918, 95991, 94948, 93777], 'i': 30, 'age': 1, 'n': 2}, [1.965733, 1.897581]], ['temporary annuity 1', {'l': [100000, 99712, 99416, 99061, 98637, 98130, 97513, 96832, 96053], 'i': 30, 'age': 0, 'n': 2}, [1.968078, 1.905169]], ['temporary annuity 2', {'l': [100000, 99756, 99437, 99029, 98581, 98058, 97481, 96805, 96011, 95126, 94098], 'i': 30, 'age': 2, 'n': 3}, [2.901372, 2.803822]], ['whole life open table', {'l': [100000, 99723, 99381, 98995, 98553, 98028, 97454, 96770, 95995], 'i': 40, 'age': 2, 'n': None}, [6.153501, 5.153501]], ['whole life closed table', {'l': [100000, 99428, 98812, 98089, 97289, 96384, 95343, 0], 'i': 35, 'age': 1, 'n': None}, [5.41582, 4.41582]], ['term beyond table', {'l': [100000, 99661, 99257, 98733, 98143, 97444], 'i': 45, 'age': 3, 'n': 10}, [2.854994, 1.854994]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99448, 98803, 98055, 97195, 96207], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.938189]]], [['temporary annuity 0', {'l': [100000, 99726, 99420, 99062, 98618, 98121, 97557, 96898, 96138], 'i': 50, 'age': 0, 'n': 2}, [1.949771, 1.85154]], ['temporary annuity 1', {'l': [100000, 99470, 98858, 98184, 97426, 96591, 95638, 94558], 'i': 30, 'age': 3, 'n': 3}, [2.890681, 2.782092]], ['temporary annuity 2', {'l': [100000, 99476, 98844, 98126, 97312, 96401, 95355, 94159, 92804], 'i': 50, 'age': 1, 'n': 2}, [1.94633, 1.84105]], ['whole life open table', {'l': [100000, 99581, 99109, 98575, 97949, 97206, 96380, 95454, 94396], 'i': 40, 'age': 2, 'n': None}, [6.117634, 5.117634]], ['whole life closed table', {'l': [100000, 99415, 98764, 98017, 97154, 96172, 95049, 0], 'i': 35, 'age': 1, 'n': None}, [5.409681, 4.409681]], ['term beyond table', {'l': [100000, 99737, 99444, 99071, 98636, 98121], 'i': 45, 'age': 3, 'n': 10}, [2.859685, 1.859685]], ['extinct age rejected', {'l': [100, 50, 0], 'i': 40, 'age': 2, 'n': 1}, 'invalid age'], ['one-year term', {'l': [100000, 99758, 99438, 99084, 98670, 98174], 'i': 60, 'age': 0, 'n': 1}, [1.0, 0.941113]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), 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 |
|---|---|---|---|
| temporary annuity 0 | [3.742817, 3.57475] | [3.742817, 3.57475] | Passed |
| temporary annuity 1 | [3.723016, 3.541994] | [3.723016, 3.541994] | Passed |
| temporary annuity 2 | [3.790978, 3.652664] | [3.790978, 3.652664] | Passed |
| whole life open table | [6.154727, 5.154727] | [6.154727, 5.154727] | Passed |
| whole life closed table | [5.408838, 4.408838] | [5.408838, 4.408838] | Passed |
| term beyond table | [2.856251, 1.856251] | [2.856251, 1.856251] | Passed |
| extinct age rejected | invalid age | invalid age | Passed |
| one-year term | [1.0, 0.938906] | [1.0, 0.938906] | Passed |
SHA-256 / 529633240b3d72ce15ffd60b60d213df9852190479053d08f90ccef63ae931a3
Verification & scope
A deterministic bounded teaching model of a stipulated toy actuarial contract. Rates are small synthetic tables, exact rationals are used where practical and floats are rounded at the output; it makes no claim of conformance with any published table, standard of practice or regulation. 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:47:14.360077+00:00.
Case digest / 29eccabd139d381b6d5f9824e6c64f8170316f8e7b91814483ea3a4c0ec7299f