Calculation catalog › Optimizer and comparisons

Optimizer schedule withdrawal by bucket annual

For each plan year, what the conversion optimizer's solution withdraws from each of its buckets: traditional (the required distribution included), inherited traditional, the tax-free bucket (Roth, cash and HSA) and the taxable bucket, in that year's nominal dollars, to the cent. The solver's plan, not the withdrawals the projection makes (withdrawals-by-category-annual), which follow the plan's withdrawal order and its own taxes.

Field: Optimizer's planned withdrawals by bucket Unit: US dollars Basis: nominal dollars Computed by: Engine Status: Complete chain

Appears in: mcp (run_optimizer.schedule.schedule[].withdrawTraditional / .withdrawInheritedTraditional / .withdrawOther / .withdrawTaxable)

Calculation records

  • Optimizer's per-year solution Model record, justified by derivation

    Purpose: What the conversion optimizer's solver plans for each year: its conversion, its withdrawal from each bucket, the gain and taxable income it books, and its year-end balances.

    Statement: strategies/optimizer.ts#optimizeSchedule publishes OptimizedSchedule.schedule, one OptimizedYear per plan year in order, from the solution HiGHS returns for the model #buildOptimizerModel writes, when the solve has one (the raw solution's primal status Feasible: an optimum, or the incumbent a node or time limit stopped at), and no rows when it has none (an infeasible model, or a limit reached before any incumbent). conversion, withdrawTraditional (the required-distribution floor included), withdrawInheritedTraditional, withdrawOther (from the tax-free bucket of Roth, cash and HSA), withdrawTaxable and taxableOrdinary are the solution's values of the year's conversion, withdrawal, sale and taxable-income columns; endTrad, endInheritedTrad, endOther and endTaxable are the four buckets' balances at the start of the next year, after the year's flows and growth, endTaxable 0 when the plan has no taxable bucket; taxableGainRealized is the published withdrawTaxable times the gain fraction min(1, max(0, 1 − the taxable basis ratio)); irmaaTier is the highest tier whose binary is above one half, 0 for none. The engine reads each value from HiGHS's raw solution, which HiGHS writes to 16 significant digits, through a wrapper around the highs package's solution writer (not the package's six-digit parse of the pretty print); each is then rounded to cents, and a column the solution does not carry reads 0. In the model, taxable ordinary income is at least the year's ordinary income base plus the taxable part of its conversion and its traditional and inherited withdrawals, less the standard deduction with the age-65 addition (and the senior deduction net of its phase-out when the solve prices it), and at least 0; minimizing tax holds it there. The tax-free withdrawal enters the model only as a difference with the surplus the year saves, which is not published, so a solution sets one of the two to 0; and a reward of one millionth of a dollar per converted dollar reports traditional drainage as a conversion, leaving withdrawTraditional at its floor unless the year needs the cash. OptimizedSchedule.conversions lists each year whose conversion is above $0.50, with the same amount, and is empty with no solution. Units: each year's nominal dollars.

    Formula: with a solution: v_t = round2(column_t); taxableGainRealized_t = round2(withdrawTaxable_t × gf), gf = min(1, max(0, 1 − basisRatio)); irmaaTier_t = max{k : b_{t,k} > 0.5}, else 0; endBucket_t = bucket_{t+1}; conversions = [(t, conversion_t) : conversion_t > 0.5]; with no solution: schedule = [], conversions = []

    • column_t: The raw solution's value of year t's conversion, withdrawal, sale, taxable-income or next-year balance column, as HiGHS writes it (16 significant digits) (unit: nominal USD) (domain: nonnegative; 0 when the solution carries none)
    • basisRatio: The opening taxable balance's cost basis over the balance, one ratio for the whole plan (unit: fraction) (domain: 0..1; 1 when not given)
    • b_{t,k}: The solution's value of year t's IRMAA tier k binary (unit: none) (domain: 0 or 1)

    Timing: every plan year of one solve

    Rounding: cents of the raw solution's value

    Limits:

    • Cents of the solution: a planned conversion of $107,028.8775 is published as $107,028.88, in schedule[] and in schedule.conversions[] alike. Which solution HiGHS returns where more than one is optimal belongs to the highs package the engine pins (1.15.2), and so does the format of its raw solution: a solve whose raw solution the engine cannot read throws an error rather than publish; an upgrade that puts any figure the evidence compares more than half a cent from the value stated here fails it.
    • A node-limit or timeout status publishes the rows of the incumbent HiGHS held when it stopped, which is not a proven optimum (optimizer-schedule-objective-and-lifetime-tax states the two limits); a solve with no solution publishes no rows, and the status says whether the model was infeasible or a limit came first.
    • The solver's plan, not what the projection of the same conversions does. The projection executes each conversion only up to what the owners' accounts hold (the cleaned schedule), funds spending in the plan's own withdrawal order and taxes each account by its own basis and rules, so its withdrawals, realized gains, taxable income and balances (withdrawals-by-category-annual, tax-realized-gains-annual, accounts-balance-per-account-annual) can differ from these in every year. The solver's buckets grow at one blended rate a year and its sale realizes one gain fraction for the whole plan.
    • withdrawOther is the net draw on the tax-free bucket when the year needs one and 0 when the year saves; the saving itself is not published and shows only in the next year-end balance (in the evidence's two-year case, $7,057.25 saved in 2027 ends as $7,410.11).
    • irmaaTier is a classification, a census exclusion; its surcharges enter the solver's lifetime tax.
    • Evidence: the two cases of optimizer-schedule-objective-and-lifetime-tax, derived by hand from the library example rmd-irmaa's facts without its qualified charitable distribution: the one-year case's conversion through the 24% bracket, required distribution, tax-free draw and year-end balances, and the two-year case's required distributions, inherited draws, sale and its gain, two tiers and saved surplus; and its two infeasible inputs, which publish no rows. A year with both a conversion and a sale, and an inherited distribution set by a divisor, are not exercised; they follow the same readout.

    Provenance: derived by claude, implemented by claude.

    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: optimizer-schedule-year-solution.md Mutation receipt: optimizer-schedule-year-solution.mutation.md

    Evidence tests: optimizer.schedule.evidence.test.ts

    Implemented in: optimizer.ts

    Is the number of: optimizer-recommended-conversion-annual, optimizer-schedule-withdrawal-by-bucket-annual, optimizer-schedule-taxable-gain-realized-annual, optimizer-schedule-taxable-ordinary-income-annual, optimizer-schedule-ending-balance-by-bucket-annual

    Feeds: optimizer-schedule-lifetime-tax, optimizer-schedule-ending-after-tax-objective, optimizer-schedule-conversion-total

Engine source: engine/src/strategies/optimizer.ts (OptimizedYear.withdrawTraditional / withdrawInheritedTraditional / withdrawOther / withdrawTaxable)

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.