Calculation catalog › Spending and withdrawals

Risk based guardrail suggested adjustment monthly

The monthly spending cut at the solved cut threshold, or raise at the solved raise threshold, that brings fixed-target Monte Carlo success back to the middle of the band: |1 − m| × base annual spending / 12, with m the eight-step bisection result for the spending multiplier.

Field: Suggested spending adjustment at a solved guardrail threshold Unit: US dollars Basis: today's dollars (real) Computed by: Engine Status: Complete chain

Appears in: assumptions-card (Spending card, risk-based guardrails callout "trimming about $X/mo restores the middle of the band" / "roughly $Y/mo of extra spending" (SpendingPolicyRiskBased.tsx RiskBasedThresholdsCallout))

Calculation records

  • Risk-based guardrail thresholds and suggested adjustments by bisection Model record, justified by derivation

    Purpose: Finds the portfolio levels where the plan's Monte Carlo success meets each edge of its success band, and the spending change that brings success back to the middle of the band there.

    Statement: Let S(f, m) be the success rate of the plan with fixed target spending, with every investable balance scaled by f and target spending by m, on shared seeded Monte Carlo paths (or the value of the optional successProbe(f, m), which replaces that run). The band is L/U percent (the plan's policy, else 70/95) and the recovery target is (L + U)/200. For each edge p = L/100 and U/100: if S(0.02, 1) >= p the outcome is always-above-band; if S(4, 1) < p it is never-reaches-band; otherwise ten bisections on [0.02, 4] move hi to the midpoint when S(mid, 1) >= p and lo otherwise, and the edge is hi, a point 0.02 + k · 3.98/1024 with k a whole number from 1 to 1024 (the smallest such point meeting p), published with balancePct = round(hi · 10,000) / 100, the percent the planner persists. At a solved lower edge f_L the suggested cut bisects m eight times on [max(0.3, required/base), 1], moving lo when S(f_L, m) >= the recovery target, and returns lo, provided the best case S(f_L, lowest m) reaches the target; at a solved upper edge the raise does the same on [1, 2], and reports m = 2 when even S(f_U, 2) stays above the target. annualDollars = |1 − m| · base spending and monthlyDollars = annualDollars / 12. For S(f, m) = min(1, f/(2m)), one $500,000 taxable account, base spending $40,000, no required spending and a 70/95 band: successAtCurrent is 0.5; the edges are k = 356 and 484, balanceFrac 1.403671875 and 1.901171875, balancePct 140.37 and 190.12; the cut multiplier is 0.849609375 ($6,015.625 a year, $501.3020833333333 a month, success after 0.8260689655172412) and the raise multiplier 1.1484375 ($5,937.50 a year, $494.7916666666667 a month, success after 0.8277210884353741); the probe is called 40 times. Units: fractions of starting investable, multipliers, today's dollars. Rounding: none; absolute tolerance 1e-12 on fractions and multipliers and 1e-6 on dollars.

    Formula: edge(p) = min { 0.02 + k · 3.98/1024 : k = 1..1024, S(·, 1) >= p } by ten bisections; m_cut = max { m on the eight-step lattice of [m_min, 1] : S(f_L, m) >= (L + U)/200 }; m_raise likewise on [1, 2]; monthly = |1 − m| · base / 12

    • S(f, m): Fixed-target success rate at balance scale f and spending multiplier m (unit: 1) (domain: [0, 1], nondecreasing in f and nonincreasing in m; worksheet min(1, f/(2m)))
    • L, U: Success band edges (unit: percent) (domain: L < U; worksheet 70 and 95)
    • k: Lattice index of a solved edge (unit: 1) (domain: whole number 1 to 1024; worksheet 356 and 484)
    • m: Spending multiplier of a suggested adjustment (unit: 1) (domain: cut [max(0.3, required/base), 1], raise [1, 2]; worksheet 0.849609375 and 1.1484375)
    • base: Base annual target spending (unit: usd) (domain: > 0; worksheet 40,000)
    • B: Starting investable (risk-based-starting-investable) (unit: usd) (domain: worksheet 500,000)

    Timing: once per solve, on today's balances and today's spending

    Rounding: none

    Limits:

    • Monotonicity of success in f and m is assumed, not checked; with a curve that is not monotone the result is a lattice point but not a meaningful edge
    • The Spending card always solves under the lognormal model at 12 percent volatility around the plan's own expected returns (allocated accounts use their asset classes' volatilities), with 200 paths and the engine's default seed (monte-carlo-default-seed), whatever model the Monte Carlo page shows; the solve stores the seed beside the thresholds, and thresholds saved before schema v6 carry none and were solved on a seed taken from the plan id, which the card says
    • Successes are cached by the balance scale rounded to 1e-6; the lattice step is about 3.9e-3, so two lattice points never share a key. The spending phase is not cached, so successAfter re-evaluates a multiplier the bisection has usually tried already
    • With a single path S is 0 or 1, so the two band edges are the same test and return the same point
    • balancePct rounds in floating point: at three of the 1,024 lattice points (k = 192, 448 and 704) the product lands just below a half and rounds down, persisting 76.62, 176.12 and 275.62 where the exact values round half up to 76.63, 176.13 and 275.63; the callouts print the persisted percent of today's balances (guardrail-threshold-dollars)

    Provenance: derived by claude, implemented by claude-subagent.

    Independent review: codex

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: risk-based-guardrail-threshold-solver.md Mutation receipt: risk-based-guardrail-threshold-solver.mutation.md

    Evidence tests: riskBasedGuardrails.evidence.test.ts

    Implemented in: riskBasedGuardrails.ts

    Is the number of: risk-based-guardrail-solved-balance-thresholds, risk-based-guardrail-suggested-adjustment-monthly

    Feeds: display-guardrail-balance-thresholds, spending-guardrail-factor-annual

Engine source: engine/src/montecarlo/riskBasedGuardrails.ts (RiskBasedGuardrailSolution.suggestedCut.monthlyDollars / suggestedRaise.monthlyDollars)

The evidence links on this page (each record's worksheet, mutation receipt, evidence tests and implementation, and the source links) are pinned to engine commit 2624dbdba9fd, committed 2026-10-11. The live calculation index and output-family census links point at the repository's main branch, so you can check this snapshot against them.