engine+ui: tax drains the portfolio + Wealthfolio-seeded NW default
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Two fixes:
(1) Simulator: portfolio drain is now `w + tax(w)`, not just `w`.
The pre-2026-05-10 engine recorded tax in tax_hist but never
subtracted it from the portfolio, so changing jurisdiction only
moved the median_lifetime_tax cell — the fan chart, success
rate, and ending percentiles were identical for UK vs Cyprus
vs Malaysia. (The PLAYBOOK_VIKTOR.md memo from 2026-04-26
explicitly noted this: "Success rate is regime-independent…
tax doesn't drain the portfolio in this simulator.")
Mental model now: spending_target is what the user takes home;
the tax bill is an additional drag on the same pool. Higher-tax
jurisdictions therefore drain faster and lower the success
rate, which is the user's intuition. Trinity 4% effectively
becomes "4% take-home + tax overhead". 188 tests still pass —
most use Malaysia (0%) or hit the regime-independent code paths.
(2) /what-if and /scenarios/new now pre-fill nw_seed_gbp from
GET /networth on first mount (when the wealthfolio_sync mirror
has data), so opening the form starts from the user's real
portfolio total instead of the £1.5M placeholder. Once the user
edits the field, subsequent NW refetches don't clobber it
(nwAutoFilled latch).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
f781afe3fa
commit
b40defacf0
3 changed files with 36 additions and 5 deletions
|
|
@ -223,7 +223,17 @@ def simulate(
|
|||
w = max(0.0, min(w, float(portfolio[p])))
|
||||
tax_breakdown = regime_at(y).compute_tax(bucket_split(w, y))
|
||||
t = float(tax_breakdown.total)
|
||||
portfolio[p] = portfolio[p] - w
|
||||
# Drain BOTH withdrawal AND tax from the portfolio. Mental
|
||||
# model: `w` is what the user takes home to spend; the tax
|
||||
# is an additional drag that comes out of the same pool. A
|
||||
# high-tax jurisdiction therefore drains the portfolio
|
||||
# faster and lowers the success rate, matching user intuition
|
||||
# (Cyprus non-dom should beat UK on outcome, not just on a
|
||||
# summary stat). Pre-2026-05-10 the engine recorded `t` but
|
||||
# didn't subtract it, so jurisdiction only changed the
|
||||
# `median_lifetime_tax_gbp` cell while the fan chart and
|
||||
# success rate were identical across regimes.
|
||||
portfolio[p] = max(0.0, portfolio[p] - w - t)
|
||||
withdrawal_hist[p, y] = w
|
||||
tax_hist[p, y] = t
|
||||
last_withdrawal[p] = w
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue