Files
sure/test
Guillem Arias 36a43f3a35 feat(retirement): PR3a FIRE forecast engine (deterministic, real-terms)
Pure-Ruby projection engine for a single plan. Models in real
(today's-money) terms: portfolio grows at the real return, spending and
pension incomes are held in today's money, so no inflation parameter is
needed and output is fully deterministic. v2 swaps in a Sidekiq Monte
Carlo behind the same call interface.

POROs (app/models/retirement/):
- Fire::Forecast — annual stepper. Accumulate (×(1+r)+savings) to
  retire_age, then draw down max(target − net pension income, 0) with
  lump payouts as portfolio deltas. Computes the glide series,
  money-lasts-to age, terminal value, Coast FIRE age (bisection on the
  minimum survivable portfolio at retirement), feasibility, warnings.
- Fire::Payout — normalises a PensionSource to gross annual income +
  one-time lump per age, across the four payout shapes.
- Fire::Adjustment — age-bounded signed change to the spending target.
- Fire::CohortAccess — min access age (UK NMPA 55→57 from 2028, US
  59.5/62, DE 63/55).
- Tax::StaticRate (+ initializer) — v1 fraction-kept by treatment;
  de_renten falls with the cohort year. Boot-validated against the
  PensionSource enum.

Wiring: Goal::Retirement gains retirement_params store_accessor
(birth_year, retire_age, real_return_pct, monthly_savings, target_spend,
terminal_age), bucket_value, payouts, forecast_inputs, memoised
#forecast (nil until birth_year set), freedom_date, coast_fire_date.
Family#retirement_spending_baseline anchors the default target on the
median monthly expense (the precise trailing-12m 10%-trimmed mean +
its label ship with PR4's "Why this target?" card).

Tests: 28 — exact zero-return stepper checks (accumulation + depletion
with shortfall), pension-covered no-drawdown, tax widening the
drawdown, adjustment lowering the target, Coast extremes, infeasible
warnings, plus tax/payout/cohort units and the model wiring. No new
gems.
2026-05-29 11:31:06 +02:00
..
2025-11-17 21:51:37 +01:00