Migrated from monorepo during Forgejo registry consolidation 2026-05-07
Find a file
Viktor Barzin edb4d11352
Some checks are pending
Build and Push / lint-and-test (push) Waiting to run
Build and Push / build (push) Blocked by required conditions
Build and Push / deploy (push) Blocked by required conditions
Build and Push / notify-failure (push) Blocked by required conditions
feat(fire-target): per-Case FIRE-number solver for the retirement countdown
Add a Monte-Carlo "FIRE number" solver so the wealth dashboard can show a £
countdown to retirement across life-stage cases, in today's money.

Viktor wants to see, per country, how far his net worth is from being able to
retire for good under three cases — Solo (his spend ×1.5), Household (+Anca
×1.5), Family (+2 kids) — with cost-of-living re-scaling per country and a 99%
Guyton-Klinger success bar.

- spend_model: per-Case real-GBP spend, COL-scaled (rent + non-rent essentials
  scale by country; Holidays fixed), ×1.5 safety. Constants sourced live from
  actualbudget (Viktor) / on-record (Anca).
- geo: city -> tax jurisdiction (nomad fallback).
- fire_target: binary-search the smallest LIQUID net worth where GK reaches the
  bar; pension modelled as a tranche unlocking at ~57, kids ramp + optional home
  as cashflows. New fire_target table (migration 0007) + idempotent upsert.
- recompute-fire-targets CLI: solve every Case x country and persist for Grafana.
- CONTEXT.md glossary + ADR-0001 (why MC-threshold on liquid NW, not 25x spend).

Reuses the existing simulator unchanged (its cashflow hooks already supported
pension/kids/home). 345 tests pass; mypy + ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 11:49:23 +00:00
.github/workflows ci: drop mypy from GHA lint job — strict-mypy drifted while unmonitored 2026-06-13 00:48:40 +00:00
.woodpecker ci: move image build off-infra to GHA -> ghcr (ADR-0002) 2026-06-13 00:44:24 +00:00
alembic feat(fire-target): per-Case FIRE-number solver for the retirement countdown 2026-06-28 11:49:23 +00:00
docs feat(fire-target): per-Case FIRE-number solver for the retirement countdown 2026-06-28 11:49:23 +00:00
fire_planner feat(fire-target): per-Case FIRE-number solver for the retirement countdown 2026-06-28 11:49:23 +00:00
frontend fire-planner: filterable date range on the home-page history chart 2026-05-28 09:04:58 +00:00
tests feat(fire-target): per-Case FIRE-number solver for the retirement countdown 2026-06-28 11:49:23 +00:00
.dockerignore deploy: combined Dockerfile — FastAPI serves the SPA in prod 2026-05-09 22:25:52 +00:00
.gitignore feat(fire-target): per-Case FIRE-number solver for the retirement countdown 2026-06-28 11:49:23 +00:00
alembic.ini Initial extraction from monorepo 2026-05-07 17:06:19 +00:00
CONTEXT.md feat(fire-target): per-Case FIRE-number solver for the retirement countdown 2026-06-28 11:49:23 +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 examples: add asyncpraw dependency (constrain aiosqlite to ^0.17 for asyncpraw compat) 2026-05-28 22:03:27 +00:00
pyproject.toml examples: orchestrator + click CLI (ingest sub-command) 2026-05-28 22:33:41 +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