whatif: drop glide-path, compact form into 4 sections
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
The What-If form was a 14-field stack with always-visible hint paragraphs — ~1500px scroll before "Run". The user is single-allocation (100% stocks), so the glide-path knob was noise. Hardcoded `static(1.0)` at the API layer; dropped `glide_path` from `SimulateRequest` (extra field on persisted Scenario rows still honoured for Cartesian sweeps). Frontend reorganised into anchor numbers (NW / spend / horizon at text-2xl), a Plan card (jurisdiction + leave-UK + strategy chips + conditional Floor/Custom sub-card), a Returns card (3-chip segmented control with inline manual %), and a folded Advanced section (savings, MC paths, seed). Verbose hints moved into ⓘ popovers next to each label. Two new primitives: SegmentedControl + InfoTip. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
f43322e5ce
commit
1d347ff65b
7 changed files with 501 additions and 299 deletions
|
|
@ -213,11 +213,16 @@ class LifeEventInput(BaseModel):
|
|||
|
||||
|
||||
class SimulateRequest(BaseModel):
|
||||
"""Sync, non-persisted simulate. Used by the React UI for what-if."""
|
||||
"""Sync, non-persisted simulate. Used by the React UI for what-if.
|
||||
|
||||
Allocation is hardcoded to 100% stocks at the engine layer
|
||||
(`api/simulate.py::_project`). The UI removed the glide-path knob
|
||||
in 2026-05; persisted Cartesian scenarios still carry their own
|
||||
`glide_path` string on the `scenario` table.
|
||||
"""
|
||||
jurisdiction: str
|
||||
strategy: str
|
||||
leave_uk_year: int = Field(ge=0, le=60)
|
||||
glide_path: str = "rising"
|
||||
spending_gbp: Decimal = Field(gt=0)
|
||||
nw_seed_gbp: Decimal = Field(ge=0)
|
||||
savings_per_year_gbp: Decimal = Decimal("0")
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from fire_planner.api.schemas import (
|
|||
SimulateRequest,
|
||||
SimulateResult,
|
||||
)
|
||||
from fire_planner.glide_path import get as get_glide
|
||||
from fire_planner.glide_path import static
|
||||
from fire_planner.ingest.wealthfolio_pg import create_wf_sync_engine_from_env
|
||||
from fire_planner.life_events import EventInput, events_to_cashflow_array
|
||||
from fire_planner.returns.bootstrap import block_bootstrap
|
||||
|
|
@ -119,7 +119,7 @@ def _project(req: SimulateRequest, paths: np.ndarray) -> tuple[SimulationResult,
|
|||
paths=paths,
|
||||
initial_portfolio=float(req.nw_seed_gbp),
|
||||
spending_target=float(req.spending_gbp),
|
||||
glide=get_glide(req.glide_path),
|
||||
glide=static(1.0),
|
||||
strategy=strategy,
|
||||
regime=build_regime_schedule(req.jurisdiction, req.leave_uk_year),
|
||||
horizon_years=req.horizon_years,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue