Migrated from monorepo during Forgejo registry consolidation 2026-05-07
Find a file
Viktor Barzin eb0dd3ddbf
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
fire-planner: life-event spending bumps now reflected in fan + auto-
refresh on scenario edits

Two fixes for the user's report that adding a £100k life-event spend
didn't change the chart:

Engine (simulator.py)
- New `extra_outflows` param. cashflow_adjustments still drains the
  portfolio at start-of-year as before, but the simulator now ALSO
  records the spending in `withdrawal_hist[p, y]` so the chart's red
  median-withdrawal trace shows the bump. Without this, the £100k
  silently came out of the portfolio but the user-facing withdrawal
  trace stayed at the strategy's flat 4% draw.
- simulate.py wires extra_outflows = essential + discretionary
  category outflows from life events.

UX (ScenarioDetail.tsx)
- New auto-refresh: when life events / income streams / flex rules
  change for a scenario, the page fires `/simulate` automatically
  with 2,000 paths and uses the result as the primary fan/year-stats
  source. The persisted MC run is only consulted as a fallback for
  scenarios with no overrides.
- Fan chart title gains a "live preview · Xs · Ny" pill while a sim
  is current, and "re-running…" while a fresh one is in flight.
- Removed the now-redundant "Live preview run" duplicate card lower
  down — the main chart IS the live preview.
- Year-stats badge row reads from sim.data when available so changes
  propagate immediately to NW / Δ NW / Spending / Taxes.

247 pytest pass (+1 new); mypy + ruff clean; frontend typecheck/test/
build green.
2026-05-10 19:17:57 +00:00
alembic fire-planner: Wave 2 chart-first — flex spending, categorised life 2026-05-10 16:49:04 +00:00
fire_planner fire-planner: life-event spending bumps now reflected in fan + auto- 2026-05-10 19:17:57 +00:00
frontend fire-planner: life-event spending bumps now reflected in fan + auto- 2026-05-10 19:17:57 +00:00
tests fire-planner: life-event spending bumps now reflected in fan + auto- 2026-05-10 19:17:57 +00:00
.dockerignore deploy: combined Dockerfile — FastAPI serves the SPA in prod 2026-05-09 22:25:52 +00:00
.gitignore Initial extraction from monorepo 2026-05-07 17:06:19 +00:00
.woodpecker.yml Phase 4: drop registry.viktorbarzin.me, Forgejo only 2026-05-07 23:17:46 +00:00
alembic.ini Initial extraction from monorepo 2026-05-07 17:06:19 +00:00
Dockerfile fire-planner: copy frontend/.npmrc before npm ci in Dockerfile 2026-05-10 16:54:25 +00:00
PLAYBOOK_VIKTOR.md Initial extraction from monorepo 2026-05-07 17:06:19 +00:00
poetry.lock Initial extraction from monorepo 2026-05-07 17:06:19 +00:00
pyproject.toml api: expand FastAPI surface for scenarios, networth, life-events, goals, simulate 2026-05-09 21:48:36 +00:00
README.md Initial extraction from monorepo 2026-05-07 17:06:19 +00:00

fire-planner

Risk-adjusted, tax-minimised FIRE retirement planner. Consumes today's portfolio, savings rate, and RSU vest schedule from sibling services (wealthfolio, payslip-ingest, hmrc-sync) and returns the after-tax probability of success for each combination of jurisdiction, withdrawal strategy, and "year you break UK tax residency".

Layout

  • fire_planner/ — package
    • tax/ — per-jurisdiction tax engines (UK, nomad, Malaysia, Thailand, Cyprus, Bulgaria)
    • returns/ — Shiller 1871+ data + block bootstrap sampler
    • strategies/ — Trinity 4% SWR, Guyton-Klinger guardrails, VPW
    • ingest/ — pulls from wealthfolio / payslip-ingest / hmrc-sync
    • simulator.py — vectorised NumPy MC engine
    • scenarios.py — Cartesian product over (jurisdiction × strategy × leave-UK-year × glide)
    • app.py — FastAPI on-demand /recompute
    • __main__.pyclick CLI: ingest, simulate, recompute-all, migrate

Common commands

poetry install
pytest -v
mypy .
ruff check .
yapf --recursive .

# Run migrations against the local DB:
DB_CONNECTION_STRING=postgresql+asyncpg://... alembic upgrade head

# CLI
DB_CONNECTION_STRING=... python -m fire_planner ingest
DB_CONNECTION_STRING=... python -m fire_planner simulate --scenario=cyprus-vpw-leave-y3
DB_CONNECTION_STRING=... python -m fire_planner recompute-all

Schema

Six tables in fire_planner schema on pg-cluster-rw:

  • account_snapshot — daily NW per account (Wealthfolio)
  • scenario — Cartesian-product scenario definition
  • mc_run — execution metadata + summary stats per (scenario, run_at)
  • mc_path — sparse storage (top decile, bottom decile, median)
  • projection_yearly — deterministic point projection per scenario
  • scenario_summary — denormalised fast-read for Grafana