VM-22 Statutory Reserves (Non-Variable Annuity) Compute statutory reserves for fixed and indexed annuities under NAIC VM-22 (PBR for non-variable annuities).
Optional 2026, mandatory 2029. Methodology adapted from VM-20 PBR for non-variable annuity products including indexed annuities and RILA. Engine TBD; component composition will mirror VM-20 with annuity-specific cash-flow logic.
Inputs, processing, outputs
Methodology
M-003 is the model card for statutory reserves on non-variable annuities — fixed deferred annuities, payout/income annuities, indexed annuities (FIA), and registered index-linked annuities (RILA) — under the NAIC Valuation Manual Section 22 (VM-22) principles-based reserve (PBR) framework. VM-22 is optional from 2026-01-01 and mandatory from 2029, and it brings non-variable annuities into the same PBR family as VM-20 (life) and VM-21 (variable annuities). It is intended to supersede the deterministic Commissioners Annuity Reserve Valuation Method (CARVM) of Actuarial Guideline IX-C / AG 33 (income-annuity and elective-benefit valuation) with a VM-21-style CTE-based stochastic reserve plus a deterministic floor.
M-003 is under_development. There is no VM-22-specific engine in InsModel today. The target architecture — a vm22_engine analogous to the VM-20 vm20_engine, composing annuity-specific cash-flow logic over the common projection harness and producing a max(net-premium floor, deterministic reserve, stochastic CTE reserve) held amount — is planned for Q2–Q3 2026 and does not yet exist. The model registry (M-003) therefore binds insmodel.L4.reserve_engine_stat (STATReserveEngine, registry ID M-101S) as an explicit placeholder, alongside mortality_engine, lapse_engine, and the projection_orchestrator.
What STATReserveEngine computes today (the CARVM/CRVM stand-in)
STATReserveEngine (firmmodel/engines/stat_reserve_engine.py, v1.0.0) implements classical NAIC CRVM and NLP statutory reserves with prescribed mortality and a single prescribed valuation interest rate. For each policy it projects, per annual duration t:
- Net valuation premium (NVP) — the level annual premium, payable at the start of each year, whose present value equals the PV of future benefits at issue:
NVP = PV(future benefits) / annuity-due(premium-paying period), computed at the valuation rate with survival-weighted prescribed mortality (_compute_net_valuation_premium). - Net Level Premium (NLP) reserve at duration
t—PV(future benefits from t) − NVP · annuity-due(remaining years)(_compute_nlp_reserve). - CRVM reserve — the NLP reserve graded linearly from 0 at issue to the full NLP reserve over the grading period (
min(max_crvm_grading_years, premium-paying period)), per_compute_crvm_reserve. CRVM ≤ NLP during grading. - Tabular cost of insurance —
face · q_x / (1 + valuation_rate)for the period. - Deficiency reserve — when the gross premium charged is below the NVP,
(NVP − gross_premium) · annuity-due(remaining years), floored at zero (_compute_deficiency_reserve). - Held reserve —
total_stat_reserve = max(0, primary_reserve + deficiency_reserve), where the primary reserve is CRVM (default) or NLP per thereserve_methodparameter.
Mortality comes from a reference-data lookup (2017 CSO) when a provider supplies it; otherwise the engine falls back to the deterministic closed form q_x = 0.00005 · 1.09^(age − 20) (_get_mortality_rates). The snapshot below uses the fallback path so it is fully reproducible with no live data.
What this is, and is not, relative to VM-22
The bound engine is a death-benefit-style life-reserve calculator: it values a face amount against mortality and a level premium. That is a faithful CRVM/CARVM-family stand-in — CARVM and CRVM share the same net-premium/prospective-reserve machinery — but it is not VM-22. It does not implement the VM-22 components that distinguish annuity PBR from a net-premium life reserve: annuity payout/income cash-flow streams and elective-benefit (GLWB/GMIB) valuation, the CTE-based stochastic reserve over a prescribed economic scenario set, the VM-22 deterministic-reserve floor, indexed-annuity (FIA/RILA) option-budget and index-credit modelling, or dynamic policyholder behaviour. Those arrive only with the planned vm22_engine. The snapshot is documented as the CRVM/CARVM stand-in pending a real VM-22 PBR engine, consistent with how M-002 documents its reserve_engine_stat binding (registry open question Q-02).
Key Assumptions and Their Justification
The registry binds four A-NNN entries for M-003. Because the bound engine is the CRVM/CARVM stand-in, the engine exercises only the prescribed valuation rate and the mortality basis directly; the lapse and indexed-credit assumptions are bound for the forthcoming VM-22 engine and are not yet consumed by STATReserveEngine.
| ID | Name | Value | Derivation | Justification / status under VM-22 |
|---|---|---|---|---|
| A-001 | Base mortality table | 2017 CSO Loaded (Male/Female), or deterministic fallback when no reference data | published_source | Mortality basis for the death-benefit leg and survival weighting of annuity cash flows. Consumed by the stand-in via the reference-data lookup; falls back to q_x = 0.00005·1.09^(age−20) when unavailable. |
| A-002 | Mortality improvement scale | MP-2021 (SOA) | published_source | Latest SOA improvement scale; under VM-22 it grades projected annuitant mortality. Not exercised by the stand-in (no improvement layer in STATReserveEngine). |
| A-010 | Base lapse curve (spread liability) | Duration-graded: 15% Y1 → 5% Y10+ | data_calibrated | Persistency basis for fixed/spread annuity surrenders; central to a VM-22 cash-flow projection. Registry-bound but not consumed by the stand-in (no decrement-driven surrender in the net-premium reserve). |
| A-011 | Base lapse curve (annuity w/ guarantees) | Duration-graded: 8% Y1 → 3% Y10+ | data_calibrated | Lower persistency assumption for guaranteed-benefit annuities; the planned VM-22 engine will layer dynamic (moneyness-driven) lapse on top. Not consumed by the stand-in. |
Operational assumptions exercised by the stand-in (engine parameters):
- Valuation interest rate — valuation_rate = 3.5%, the prescribed maximum statutory valuation rate (SVL). Single flat rate; VM-22 uses a prescribed scenario-dependent discount structure.
- Reserve method — CRVM (default); NLP available. CRVM grades the reserve from 0 over min(20, premium-paying period) years.
- Deficiency reserve — enabled; triggers only when gross premium < NVP (zero in the canonical run, where the funding premium exceeds NVP).
- Mortality source — deterministic fallback formula in the snapshot (no live reference data), making the result reproducible.
Honesty note: A-002, A-010, and A-011 are bound in the registry for the intended VM-22 model but are inert in the engine that runs today. This is the single largest gap between this card's assumption table and the engine's actual behaviour, and is restated in Limitations.
Output Snapshot
Deterministic single-policy run of the real VM22ReserveEngine v1.0.0 on a canonical FIA — reproducible (python scripts/model_snapshots.py M-003 in InsModel; exercised by tests/test_vm22_reserve_engine.py). The stochastic leg consumes the ratified GOES set (M-120 / RAT-120-v1.0.2, seed 42, amp 4.3).
Input: issue age 60 · account value $250,000 · FIA · participation 50% · cap 8% · guaranteed 1% · surrender-charge 7yr · valuation rate 3.5% · deterministic rate 4.5%.
| output | value | meaning |
|---|---|---|
| carvm_reserve | 226,884.06 | CARVM greatest-present-value elective-benefit floor (AG IX-C / AG 33) |
| deterministic_reserve | 227,245.41 | VM-22 deterministic reserve (single prescribed scenario) |
| cte_stochastic_reserve | 282,140.77 | CTE70 stochastic reserve over 50 GOES scenarios |
| vm22_reserve (held) | 282,140.77 | max(CARVM, deterministic, CTE70) — the held VM-22 reserve |
| reserve_basis | stochastic_cte | the binding leg (the stochastic tail exceeds the deterministic floor) |
| account_value | 250,000.00 | annuity account value |
The held reserve is ~113% of the account value — economically credible for an annuity statutory reserve (account value plus a guarantee/tail load), unlike the prior CRVM life stand-in which produced ~312 on the same $250k policy. The CTE70 leg binds above the deterministic floor, exactly the VM-22 greatest-of mechanic.
Captured 2026-06-28 · deterministic legs need no live data; stochastic leg uses the gitignored GOES CSVs (regenerable via scripts/generate_goes_scenarios.py).
Limitations and Known Gaps
2026-06-28 update. Limitations 1–5 below described the CRVM stand-in and are now largely closed by the real
VM22ReserveEngine(held = max(CARVM floor, deterministic, CTE stochastic over GOES); FIA/RILA index-credit live; A-002/A-010/A-011 now real engine levers — closes INV-002 / INV-012). Limitation 7 (no firm 10-K back-test, BV-032) remains open. The remaining honest gaps in the real engine are itemized invalidation_evidence/M-003/v1.0.0/README.md §4(prescribed-ERP deterministic assumption is first-order; surrender-charge schedule is representative; annuitization is a greater-of(AV, GBB) proxy; the richer P-003 option-pricing is not yet composed). The historical list is retained below.
- Model is
under_development— there is no VM-22-specific engine. The registry status for M-003 isunder_development(planned implementation Q2–Q3 2026; mandatory 2029). Novm22_engineexists. Every number in this card comes from a placeholder engine and must not be read as a VM-22 reserve. [2026-06-28: CLOSED —VM22ReserveEngine(M-101A) built and 2L-approved (RAT-003-v1.0.3); status promoted toactive. The current Output Snapshot / Validation Packet are produced by the real VM-22 engine; the placeholder caveat applies only to the retained historical stand-in sections.] - The bound engine is a CRVM/CARVM life-reserve stand-in, not annuity PBR.
insmodel.L4.reserve_engine_stat(STATReserveEngine, M-101S) computes net-premium / CRVM statutory reserves against a face amount and mortality. It does not model annuity payout/income streams, account-value accumulation, or the CARVM elective-benefit greatest-present-value test (AG IX-C / AG 33). It is documented as a stand-in only, paralleling M-002's Q-02 caveat for the same engine binding. - No stochastic reserve and no deterministic VM-22 floor. VM-22 PBR is a CTE-based stochastic reserve over a prescribed economic scenario set, floored by a deterministic reserve. Neither the scenario generation, the CTE aggregation, nor the deterministic floor exists for M-003. (M-002's
C3Phase2Engineprovides CTE mechanics for variable annuities, but it is not wired to M-003 and is not a non-variable-annuity engine.) - No indexed-annuity (FIA / RILA) modelling. Fixed indexed annuities and RILAs require option-budget, index-credit, cap/participation, and buffer/floor mechanics. None of this is present; the stand-in treats the product as a fixed death-benefit contract.
- Bound lapse and improvement assumptions are inert. A-002 (mortality improvement), A-010 and A-011 (lapse curves) are registry-bound for the intended VM-22 model but are not consumed by STATReserveEngine. Dynamic (moneyness-driven) policyholder behaviour, central to annuity PBR, is absent.
- Reserve reflects only a mortality leg, not the annuity liability. Because the engine values a net-premium death benefit, the held reserve runs off to zero at the end of the premium-paying period and is small relative to the account value. A VM-22 reserve would hold the accumulation and guaranteed-payout liability; the magnitudes here are not comparable to a real annuity statutory reserve.
- Not validated against firm 10-K data. No 10-K reconciliation is claimed. The firm-financials path is divergent (finding BV-032); the snapshot is a synthetic canonical run with mock data only.
Remediation tracked (gated — requires engine/output changes, left for ratification, not applied in this documentation pass): INV-002 (build a real CARVM / VM-22 PBR engine with CTE stochastic reserve, deterministic floor, annuity payout & FIA/RILA mechanics — the substantive capability gap behind Limitations 1–4); INV-012 (thread the bound decrement curves A-010/A-011 and improvement scale A-002 into the engine, or relocate them to the upstream liability-projection step that consumes them — they are registry-bound but inert today, Limitation 5); and producing the VM-22 back-test / sensitivity evidence now shown as "pending/missing" in the Validation Packet.
Validation Packet
| evidence | status | reference |
|---|---|---|
| Deterministic snapshot | present | scripts/model_snapshots.py M-003 (reproduces the Output Snapshot above). |
| Engine unit + mechanics tests | present | tests/test_vm22_reserve_engine.py — 28 tests: contract, greatest-of mechanic, CARVM elective-option behaviour, FIA/RILA index-credit + option budget, A-002/A-010/A-011 bindings, CTE hand-calc + monotonicity. |
| VM-22 engine | present | VM22ReserveEngine (insmodel.L4.vm22_engine, M-101A), built 2026-06-28 (INV-002). |
| Frozen VM-22 gold regression | present | tests/test_vm22_reserve_engine.py::TestVM22GoldDeterministic (CI-gated, no data) + ::TestVM22GoldStochastic (50-scenario GOES, seed 42 amp 4.3; data-gated). |
| VM-22 sensitivity suite | present | ::TestVM22AssumptionBindings + ::TestVM22IndexCredit (top-3 levers: A-002 mortality improvement, A-010/A-011 lapse, index-credit/option-budget). |
| Validation evidence pack | present | insightalm/modelling/validation_evidence/M-003/v1.0.0/README.md (clears COND-001/COND-002). |
| Independent challenge (2L) | APPROVED | RAT-003-v1.0.3 (2026-06-28) — model-lifecycle-reviewer 2L effective challenge approved the build; status promoted to active. |
| Back-test vs disclosed reserves | missing | Honest gap — blocked on firm annuity-reserve data (BV-032). Honesty anchor is the frozen synthetic gold, not firm data. |
Model-vs-reality back-testing (SR 26-2 ongoing; canonical record backtest_results.yaml): records BT-012 and BT-013 are keyed to the engine insmodel.L4.reserve_engine_stat at the firm-book level, which M-003 shares with M-002 (model_membership: [M-002, M-003]). They co-validate the shared STATReserveEngine firm-book reconciliation, not M-003's own held reserve. This distinction matters for M-003 specifically: the stand-in's held number is a mortality-leg net-premium reserve (Limitations 6–7), which is not the VM-22 annuity reserve and is not comparable to a filed annuity statutory reserve — so it is not the figure being reconciled to filed reserves.
For context, the shared firm-book records read: under Decision 048 (A4-30) the aggregate reserve is reconciled to filed reserves through the firm-calibrated book — each firm's canonical segment-reserve decomposition (DS-073), not a notional cohort. Record BT-012 (status: covered) reconciles the firm-book reserve aggregate to reported policy reserves by reportable segment, superseding the earlier Mock-notional 0% (BT-011). Predictive record BT-013: at quarterly cadence a reserve roll-forward is benchmarked against naive persistence (~3.4% q/q baseline), which a structural roll-forward beats only where segment flows are cleanest.
For M-003 the honest state is: reserve back-test pending a real VM-22 engine. The BT-012 firm-book reconciliation co-validates the shared STATReserveEngine; it does not validate the VM-22 annuity reserve, which has no engine to back-test (see Validation Packet rows "VM-22 engine: missing" and "Back-test vs disclosed reserves: missing"). Sign-off requires a real VM-22 PBR engine and a back-test against disclosed VM-22 / annuity reserves.
References
Regulatory:
- NAIC Valuation Manual VM-22 — Statutory Maximum Valuation Interest Rates / PBR for non-variable (fixed and indexed) annuities; optional 2026-01-01, mandatory 2029.
- NAIC Actuarial Guideline IX-C / AG 33 (CARVM) — Commissioners Annuity Reserve Valuation Method; deterministic valuation of annuity benefits and elective benefits, the framework VM-22 PBR supersedes.
- NAIC Standard Valuation Law (SVL) — prescribed maximum statutory valuation interest rate (the valuation_rate parameter).
- NAIC Valuation Manual VM-G / VM-31 — governance and documentation taxonomy for PBR.
- ASOP No. 56 — Modeling (intended use, sensitivity, reliance, documentation).
Source code:
- Engine (registry-bound, current): ecosystem/InsModel/Models/firmmodel/engines/vm22_reserve_engine.py (VM22ReserveEngine, insmodel.L4.vm22_engine, registry id M-101A) — the real VM-22 PBR engine: CARVM greatest-PV floor, deterministic reserve, CTE stochastic reserve over GOES, FIA/RILA option-budget + index-credit.
- Tests: ecosystem/InsModel/Models/tests/test_vm22_reserve_engine.py.
- Snapshot generator: ecosystem/InsModel/Models/scripts/model_snapshots.py (snap_M_003, python scripts/model_snapshots.py M-003).
- Historical (superseded stand-in): firmmodel/engines/stat_reserve_engine.py (STATReserveEngine, M-101S) — CRVM/NLP life statutory reserves, the former CARVM/CRVM stand-in (retained for the historical sections below).
Internal:
- Model registry entry M-003 (status active; engine binding insmodel.L4.vm22_engine; lifecycle.ratification_ref: RAT-003-v1.0.3): insightalm/modelling/model_registry.yaml.
- Decision 018 (MRM Framework); Decision 020 (Assumption Policy).
- Finding BV-032 — firm-financials path divergence (no 10-K reconciliation claimed).
Change Log
Card change history. Code-side change history lives in git log of the component files.
- 2026-05-08 — stub created from registry data per Decision 023 Phase 5 / B-07.
-
2026-05-09 — added DS-018 + DS-062 references and Standards Coverage section per Stage B (DG-005 closure); Methodology / Key Assumptions / Validation sections remain stubbed for actuarial author follow-on.
-
2026-06-04 — Validation Packet: added the model-vs-reality back-test reference (BT-012 firm-calibrated reserve reconciliation; BT-013 predictive vs persistence) per A4-30 / Decision 048. SR 26-2 ongoing back-testing now documented on the card.
- 2026-06-28 — Real VM-22 engine built (INV-002, 1L model-builder per Decision 053). Bound
VM22ReserveEngine(insmodel.L4.vm22_engine, M-101A) in place of the CRVM stand-in. Implements held = max(CARVM greatest-PV floor, deterministic reserve, CTE stochastic reserve over GOES M-120/amp 4.3); FIA/RILA option-budget + index-credit mechanics; A-002/A-010/A-011 now live engine levers (closes INV-012). Updated Output Snapshot (FIA, held 282,140.77 CTE-bound), Validation Packet (engine/gold/sensitivity now present), Limitations (1–5 closed, 7 open), and added the validation_evidence/M-003/v1.0.0 pack. Registry: engine binding swapped, M-120 dependency declared, validation_evidence → present. Status staysunder_developmentpending 2L promotion (1L does not self-ratify). Earlier stand-in sections retained for history with the supersession banner at the top. - 2026-06-06 — Documentation pass (safe fixes only; no engine/output changes): added the Dependencies section (13-section gold-standard order; honest "no upstream-model dependencies declared", planned
vm22_engineGOES-style scenario dependency, no current downstream consumer per R-24 element 8). Reconciled the Validation Packet BT-012/BT-013 paragraph with Limitations 6–7 — clarified these records are keyed to the sharedSTATReserveEnginefirm-book (shared with M-002), not to M-003's held mortality-leg reserve; honest state is "reserve back-test pending a real VM-22 engine". Added a sentence to Standards Coverage explaining it is broader than the registryregulatory_frameworksregime tags, flagging ASOP_52 / VM_31 as intended-model standards not yet exercised. Noted gated remediation (INV-002, INV-012, VM-22 back-test evidence) under Limitations as tracked-for-ratification. Engine-governance cross-check filed separately:engine_registry.yamlpath forinsmodel.L4.reserve_engine_statpoints atfirmmodel/engines/reserve_engine.py(which holds the LDTIReserveEngine); the actualSTATReserveEnginelives infirmmodel/engines/stat_reserve_engine.py, which this card cites correctly — registry path fix is outside the card.
Open findings (3)
Independent 2nd-line review (INV-2026-06) — implemented capability vs registered scope. Each carries a recommended fix and is tracked in insightalm-mrm until closed.
VM-22 has no VM-22 engine (CRVM life stand-in)
M-003 (Non-Variable Annuity statutory) is status under_development and binds reserve_engine_stat (STATReserveEngine), a CRVM *life* death-benefit reserve calculator. It values a mortality leg that runs off to zero at end of premium-paying period, not an annuity accumulation/payout liability. There is no CARVM or VM-22 PBR engine.
Recommendation: Build a CARVM engine for fixed/payout annuities (greatest-present-value of guaranteed benefit streams) as the near-term statutory basis, with a VM-22 PBR path as the roadmap target. Until then keep status under_development and label the card a CRVM stand-in (done). Add the engine to engine_registry as E-NNN.
Validation evidence + change logs missing across most of the inventory
Only M-001/M-020/M-050 carried full documentation packs before this pass. Most models record validation_evidence: missing and change_log: missing with peer_review: pending. Gold tests freeze behaviour but many assert only structural invariants (e.g. reserve>0), not correctness against external truth. The flagship T0-vs-10-K match is circular (BV-032).
Recommendation: For each Tier-1 model: produce a validation-evidence pack (back-test vs disclosed results once BV-032 re-calibration lands, sensitivity suite, challenger comparison), a change log, and a 2L ratification. Sequence behind BV-032 (firm-data) for anything needing 10-K reconciliation.
Lapse/mortality curves bound but not consumed by the engine
M-003 binds lapse curves (A-010/A-011) that STATReserveEngine never reads; M-004 lists mortality/lapse among components but CFTEngine takes a pre-computed liability-CF dict, so they enter (if at all) upstream, not inside the engine.
Recommendation: Thread the bound decrement curves into the engines (M-003 once a CARVM/VM-22 engine exists, INV-002), or move the bindings to the upstream liability-projection step that actually consumes them.
Per-tier expectations
Per MRM Framework §10.2 + §10.3, this model's regulatory_frameworks tag list activates the following overlays:
| component | tier-1 expectation | status |
|---|---|---|
| Registry entry | required | present |
| Model card (§10.5 doc pack) | required | present |
| Validation evidence | required | present |
| Change log | required | present |
| Independent effective challenge (2L) | required | attested |
Ratified — RAT-003-v1.0.3
Latest ratification on file: RAT-003-v1.0.3. Authored by 2L (mrm-peer-reviewer) per Decision 028 charter §5 Pattern A.