fire-planner/fire_planner/api
Viktor Barzin e72fd22a17 col: simulator auto-adjusts spending to local prices via Numbeo+Expatistan
The Monte Carlo used to compare jurisdictions at a flat London-equivalent
spend, which silently overstated the cost-of-living for any move to a
cheaper region. Now every cross-jurisdiction simulation auto-scales
spending_gbp by the real Numbeo/Expatistan ratio between the user's
baseline city and the target city.

Architecture:
- fire_planner/col/baseline.py — 22 cities with headline Numbeo data
  (source URLs + snapshot dates embedded) — fallback when scraper fails
- col/numbeo.py + col/expatistan.py — httpx async scrapers, regex-parsed,
  polite 1.1s rate-limit, EUR/USD anchored
- col/cache.py — PG-backed cache (col_snapshot table, 1-year TTL)
- col/service.py — sync compute_col_ratio() for the simulator; async
  lookup_city_cached() with source reconciliation for the refresh CronJob
- alembic 0005 — col_snapshot table, UNIQUE(city_slug, source_name)

Simulator wiring:
- SimulateRequest gains col_auto_adjust=True (default), col_baseline_city,
  col_target_city. Defaults pick the jurisdiction's representative city.
- _resolve_col_adjustment scales spending_gbp before path-building.
- SimulateResult surfaces col_multiplier_applied + col_adjusted_spending_gbp.

CLIs:
- python -m fire_planner col-seed — loads BASELINES into col_snapshot
  (post-migration seed step)
- python -m fire_planner col-refresh-stale --within-days 7 — used by the
  weekly fire-planner-col-refresh CronJob

268 tests pass. Mypy strict + ruff clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 14:14:57 +00:00
..
__init__.py api: expand FastAPI surface for scenarios, networth, life-events, goals, simulate 2026-05-09 21:48:36 +00:00
auth.py api: expand FastAPI surface for scenarios, networth, life-events, goals, simulate 2026-05-09 21:48:36 +00:00
cashflow.py fire-planner: ProjectionLab parity Wave 1 — tabbed shell, year stats, goals, 2026-05-10 12:49:44 +00:00
dependencies.py api: expand FastAPI surface for scenarios, networth, life-events, goals, simulate 2026-05-09 21:48:36 +00:00
goals.py api: drop bearer-token gate from /api/* CRUD + simulate 2026-05-09 23:56:37 +00:00
income_streams.py fire-planner: ProjectionLab parity Wave 1 — tabbed shell, year stats, goals, 2026-05-10 12:49:44 +00:00
life_events.py api: drop bearer-token gate from /api/* CRUD + simulate 2026-05-09 23:56:37 +00:00
networth.py api: expand FastAPI surface for scenarios, networth, life-events, goals, simulate 2026-05-09 21:48:36 +00:00
progress.py fire-planner: ProjectionLab parity Wave 1 — tabbed shell, year stats, goals, 2026-05-10 12:49:44 +00:00
scenarios.py fire-planner: UX review pass 1 — fix sidebar/route/PATCH/badges issues 2026-05-10 17:17:55 +00:00
schemas.py col: simulator auto-adjusts spending to local prices via Numbeo+Expatistan 2026-05-22 14:14:57 +00:00
simulate.py col: simulator auto-adjusts spending to local prices via Numbeo+Expatistan 2026-05-22 14:14:57 +00:00
spending.py whatif: live data refresh, inflation-adjusted spending, legend fix 2026-05-10 11:27:22 +00:00
spending_profile.py fire-planner: What-If gains the chart-first scenario editor 2026-05-12 19:35:28 +00:00
year_stats.py fire-planner: ProjectionLab parity Wave 1 — tabbed shell, year stats, goals, 2026-05-10 12:49:44 +00:00