Changelog

A complete record of every update shipped to RetIQ. Newest first. No entries are ever removed.

v7.10.0
Wage-only local tax handled automatically, and a state tax rate you can set yourself

Local and county income tax for wage-only states is now handled automatically. In Ohio, Pennsylvania, Kentucky, and Missouri — where local income tax falls on wages, not on pensions, IRA or 401(k) withdrawals, or Social Security — RetIQ now applies your local rate to earned income only. A retiree with no wages correctly owes no local tax there, while someone still working has it applied to their wages. Every other state continues to apply the local rate to your full state taxable income, as before.

You can also set your own state tax rate. On the Assumptions tab, any state with an income tax now shows RetIQ’s modeled effective rate, with an option to replace it with your own number — handy if you know your real effective rate or want to match a tax return. The override applies a flat rate to your income in place of the bracket model; any county or city tax you’ve entered still applies on top. It’s off by default, so nothing changes unless you turn it on.

v7.9.0
Local and county income tax for states beyond Maryland

You can now add a local or county income tax rate for states other than Maryland. If your city or county taxes income on top of the state — common in much of Ohio and Pennsylvania, and parts of Indiana, Kentucky, and Missouri — enter that rate on the Assumptions tab and it’s added on top of your state tax, with the projection breaking it out as “State & Local Tax.” It defaults to zero, so nothing changes unless you set it, and Maryland’s local-rate field works as before. Note that some local taxes apply only to wages, not retirement income.

The Strategy Report’s relocation suggestion now refers to “a no-income-tax state” instead of naming Florida specifically — the estimated savings are the same for any no-income-tax state, so the wording no longer implies a particular destination.

v7.8.2
Projection table — every column now has a tappable info marker

Each column header in the Projection data table now shows a small info marker. Hover it on a computer or tap it on a phone to see a plain-language explanation of what that column includes and how it relates to your Expenses total. This covers every column — including the withdrawal-detail, harvesting, inherited-account, QLAC, and charitable-bunching columns — and replaces the older hover-only tooltips, which appeared slowly and did not work on touch devices.

v7.8.1
Projection table — column headers now explain each column

Hover over any column header in the Projection data table for a short explanation of what that column includes — for example, that working-year Expenses use your Pre-Retirement amount, that Debt and Long-Term Care are part of the Expenses total rather than added on top of it, and that one-time costs sit in their own column. It makes it easier to trace each number back to where you entered it.

v7.8.0
Retirement timing corrected for later-in-the-year birthdays

When you set a specific Month of Retirement, RetIQ could place your retirement one calendar year too late if your birthday falls later in the year — and carry your earned income an extra year in the projection as a result. The retirement date shown on the Personal tab and the income in your projection now reflect the year you actually retire. Plans left on “Not sure / no specific month” were never affected.

v7.7.0
A spouse’s QLAC now counts toward net worth

For couples where the non-primary spouse holds a QLAC — a deferred annuity held inside a retirement account — that balance is now included in your net worth, the same way the primary account holder’s QLAC already was. If this applies to you, your net worth will show higher than before, correcting an asset that was previously left out.

v7.6.0
Projection table — Debt, Long-Term Care, and a Net Worth breakdown

The Projection data table now shows Debt and Long-Term Care as separate columns, broken out from your total Expenses so you can trace each one back to where you entered it. Both are included in the CSV export, and both are part of the Expenses total rather than added on top of it.

Net Worth in the Projection table is now clickable — click any year's value to expand a breakdown of how it splits across your accounts: Pre-Tax, Roth, Cash/HYS, Brokerage, HSA, inherited accounts, and QLAC.

v7.5.0
Long-term care — plan for each spouse separately

You can now model a separate long-term care need for each spouse, each with its own start age, duration, annual cost, and insurance. Care for your spouse is timed to their age, not yours, and if both of you need care in overlapping years the costs add together. Households with a single long-term care scenario see no change.

v7.4.0
Roth Optimizer now weighs ACA subsidies

The optimizer tests the new Cliff-Aware Fill strategy and shows two new columns: ACA Kept (how much Marketplace subsidy a strategy preserves) and NIIT (Net Investment Income Tax paid). The optimizer's ranking now also accounts for ACA subsidies retained — so if you buy Marketplace coverage in early retirement, the recommended strategy may change to one that protects those subsidies. Households not on a Marketplace plan will see effectively the same ranking as before.

v7.3.0
New Roth conversion strategy — Cliff-Aware Fill

A new strategy that fills your target tax bracket each year while holding your income below the thresholds that matter most: the ACA Marketplace subsidy cliff, Medicare's IRMAA surcharge tiers, and the Net Investment Income Tax threshold. Useful in the pre-Medicare years when a large conversion could cost more in lost ACA subsidies than it saves in tax. The ACA ceiling is adjustable, and the NIIT guard can be switched off.

v7.2.0
ACA plan cost — model the plan you'll actually buy

On ACA Marketplace coverage you can now enter the annual premium of the plan you'll actually enroll in. RetIQ keeps your premium tax credit based on the benchmark Silver plan and applies it to your plan, so a lower-cost Bronze plan shows its true net cost. The Year-1 preview now shows your plan premium and net cost side by side.

Also fixed: for single-person households, the Benchmark Premium Override now correctly flows into the projection.

v7.1.2
Expenses shown consistently across the Dashboard and Projection tabs; one-time expenses now visible

The Expenses figure on the Projection tab now matches the Dashboard's Income vs Expenses chart. Previously the Projection tab subtracted healthcare and Medicare costs from its Expenses number while the Dashboard showed the full total, so the same plan appeared to have two different expense figures. Both now show your complete annual spending. In the Projection table, the Healthcare, Medicare, and IRMAA columns break out parts of that total rather than adding to it.

One-time expenses now appear in the Projection table and chart as their own "One-Time" line. Previously a one-time expense reduced an account balance silently, with nothing in the projection showing where the money went; you can now see it year by year.

v7.1.1
Net Worth chart: zero-balance account lines no longer cover the account below

On the Dashboard Net Worth chart, when an account was drawn down to zero — for example a Brokerage balance emptied by Roth conversions or withdrawals — that account's line was still drawn directly on top of the account line stacked beneath it, hiding the lower account (such as Roth) for those years. The chart now draws each account's line only for the years that account actually holds a balance, so every account with a balance stays visible.

v7.1.0
Retirement month accuracy

The Month of Retirement field now accounts for your birth month. If you retire in a month that falls before your birthday, RetIQ places your retirement in the following calendar year — so the retirement date shown on the Personal tab matches the year you actually retire.

The retirement-month dropdown now includes a “Not sure / no specific month” option. Choosing it keeps your projection on a whole-year basis, exactly as before. Existing plans are unchanged on load — they stay on the whole-year basis and only adopt the new behavior if you pick a specific month.

One-Time Income Events now warn you when an event’s age falls outside your projection range — before your current age or after your plan ends — so a severance or bonus entered against the wrong age no longer disappears without explanation.

v7.0.3
Percent-of-income contribution routing

Contribution Routing now lets you enter your 401(k) and IRA contributions as a percentage of your income instead of a fixed dollar amount. A new toggle on the routing card switches between "$ Amount" and "% of Income." In percent mode, your contributions automatically rise and fall with your income each year — including through raises and any pay-cut years you've modeled with Pre-Retirement Income Phases — with no extra steps. Dollar-amount routing stays the default, and existing plans are unchanged.

v7.0.2
Fix: Routed contributions could exceed your available savings

When Contribution Routing was turned on, the projection could direct more money into 401(k) and IRA contributions than your savings for that year actually covered. Two situations caused this. If your routed contributions came to more than your savings, the engine funded them in a fixed order, so one spouse’s contributions and employer match could be cut to nothing before the other spouse’s were reduced at all. And when one spouse used Contribution Routing while the other used the default allocation, the routed spouse’s contributions could draw against the other spouse’s savings, pushing the household’s total contributions above its total savings. Both are now corrected: when routed contributions exceed available savings, each one is scaled down proportionally, and a routed spouse’s contributions are limited to that spouse’s own savings. Projections where contributions always fit within savings are unchanged. If you use Contribution Routing — especially with a reduced-income phase, or with one spouse routing and the other not — re-check your plan, since the corrected projection may show a lower contribution total.

The Contribution Routing card’s savings warning is now phase-aware. It previously checked only your current annual savings; it now checks every year through retirement, including reduced-income phases, and shows which years your routed contributions would exceed your savings. The card also states plainly that routed 401(k) and IRA amounts are fixed dollar contributions that do not grow from year to year. And the Annual Savings fields gained help text noting that this figure grows each year at your savings growth rate, and pointing to Pre-Retirement Income Phases as the way to use a different amount for a specific age range.

v7.0.1
Fix: Healthcare tab pre-Medicare cost estimate

The Healthcare tab displayed two pre-Medicare healthcare cost totals — a headline estimate and the year-by-year Cost Summary below it — calculated by separate code paths that could disagree. The headline estimate is now drawn from the same projection as the Cost Summary, so the two always match. Only the headline estimate changed; the Cost Summary figure was already correct. This affected plans that retire before Medicare eligibility.

v7.0.0
Survivor scenario rework

This release completes the survivor-scenario rework. Planning for the loss of a spouse is now a clear, guided part of the app — you can model what happens if either spouse passes at an age you choose, see the financial picture the survivor would face, and carry that scenario forward as your active plan. Labels and section headings throughout the Survivor area have been rewritten to plainly say what each part does.

v6.62.6
Fix: pre-tax balance growth after a spouse’s death

Corrected an error where, after the first spouse died, the surviving spouse’s pre-tax (Traditional IRA / 401k) balance could grow at the plan’s default Nominal Return rate even when the underlying accounts were set to a different return rate. The growth rate now always follows the accounts that actually hold the money. This affected projections where one spouse held all the pre-tax savings and the other held none. Plans where both spouses hold pre-tax balances, and plans without a death in the projection, were not affected.

v6.62.5
Fix: pre-tax balance accuracy in survivor scenarios

Corrected an error in how the pre-tax (Traditional IRA / 401k) balance was tracked after the first spouse’s death. The surviving-spouse share of the pre-tax pool was grown as a separate figure from the pool itself, which could let the two diverge once an inherited IRA rolled over — producing small inaccuracies in the displayed pre-tax balance and in required minimum distributions in later years. The share is now always derived directly from the pool, so the two cannot drift. Plans without a death in the projection are unaffected.

v6.62.4
v6.7 — Life Expectancy: projections now reflect mortality

This entry summarizes the v6.7 release, delivered across the five point releases below (v6.61.2 through v6.62.3). Life Expectancy is no longer just a Survivor-tab input — it now drives the entire projection.

What changed. When you set Life Expectancy on the Personal tab to an age below Plan Through Age, the projection reflects that death: after the death age, the plan continues as a single-survivor scenario. Medicare drops to one enrollee, filing status shifts to Single, Social Security survivor benefits apply, expenses adjust by the survivor ratio, and any configured life insurance death benefit deposits tax-free. Healthcare costs, IRMAA, lifetime taxes, end-of-life net worth, and every analytical tool — Strategy Report, Roth Optimizer, Monte Carlo — reflect this automatically.

If you never set Life Expectancy, nothing changed: both spouses are still assumed alive through Plan Through Age, exactly as before. The feature is opt-in by setting the fields.

New transparency. The Healthcare tab gained a per-spouse Medicare & IRMAA detail table. The Survivor tab’s Three Futures and Robust vs Fragile views were repositioned so their “upper bound” column is an explicit comparison rather than a hidden assumption. The Personal tab Life Expectancy card explains the engine behavior directly.

See the five entries below for the per-release detail. No engine or behavior change ships with this v6.62.4 entry itself — it is the consolidated summary plus documentation refinements.

v6.62.3
Strategy resilience & term-life checks aligned with Life Expectancy

Two refinements completing the v6.7 Life Expectancy work. The Survivor tab’s Strategy Resilience — Robust vs Fragile table now labels its first column Both Reach Plan End and computes it as a true upper bound (both spouses alive through Plan Through Age), consistent with the Three Futures table. Previously, when Life Expectancy was set, that column silently reflected LE-driven mortality.

The Strategy Report’s term-life-insurance warning — which flags a term policy that expires before the modeled death age — now also accounts for Life Expectancy. Previously it only fired for explicit Survivor-tab scenarios; a plan with Life Expectancy set but no Survivor scenario received no warning even when its term coverage lapsed early.

A full review confirmed the Strategy Report Card, Roth Optimizer, and Monte Carlo all already handle Life Expectancy correctly — their baseline and every alternative run against the same plan, so comparisons stay consistent. No changes were needed there. No engine changes; all test suites pass at baseline.

v6.62.2
Survivor tab repositioned around Life Expectancy

The Survivor tab’s three sub-tabs now reflect the post-v6.7 reality where Life Expectancy drives the projection by default. Three Futures at a Glance: the first column is now labeled Both Reach Plan End and overrides Life Expectancy for that column only, showing the upper-bound comparison. The other two columns continue to use Survivor scenarios with LE inherited from plan params for the non-selected spouse.

Survivor Impact Analysis: description reframed from “model death” to “test what happens if death occurs at a different age than your configured Life Expectancy.” When LE is set on the Personal tab, a small blue inline note now appears showing the assumed ages so users can see what the analysis is overriding.

Adopt Plan: added a clarifying note explaining when to use Adopt Plan (death has happened or is imminent) versus setting Life Expectancy on the Personal tab (modeling a future death age that hasn’t happened yet).

No engine changes; all six test suites pass at baseline.

v6.62.1
Per-spouse Medicare & IRMAA detail panel

New Per-Spouse Medicare & IRMAA Detail card on the Healthcare tab. Breaks down each year’s Medicare costs by enrollee — base Part B premium, Part B IRMAA surcharge, and Part D IRMAA surcharge — alongside the household total. For couples, both spouses appear side-by-side; for single filers, the table collapses to one column per cost type. Death transitions surface as zeroed cells, making the survivor scenario behavior visible at a glance. Note: base Part D plan premiums are user-paid privately and are not modeled by the engine; only the income-based IRMAA surcharge on Part D appears.

The lifetime-totals footer below the Medicare summary now reflects the actual life expectancy assumption: when Life Expectancy is set, the footer reads “Reflects life expectancy: you to age X and spouse to age Y. After each death age, the plan continues as a single-survivor scenario” (Medicare drops to one enrollee, filing shifts to Single, Social Security survivor benefits apply). When Life Expectancy is not set, the footer continues to note that both spouses are assumed alive through Plan Through Age and links to the Personal tab.

Engine: per-enrollee Medicare values now expose on year rows as y.partBBasePrimary, y.partBBaseSpouse, y.partBIrmaaPrimary, y.partBIrmaaSpouse, y.partDIrmaaPrimary, y.partDIrmaaSpouse. Existing y.medicareCost and y.irmaa household totals are unchanged; the six new scalars sum to y.medicareCost + y.irmaa within rounding. 9 new tests in test-mortality-resolution.js verify the exposure, MFJ-MAGI bracket sharing, single-filer collapse, post-death zeroing, consistency with household totals, and inflation accuracy.

v6.62.0
Life Expectancy now drives your projection (v6.7 begins)

The Life Expectancy values on the Personal tab now drive your full projection — not just the Survivor tab. After each spouse’s death age, the plan continues as a survivor scenario: Medicare drops to one enrollee, filing shifts to Single, Social Security survivor benefits apply, and Medicare/IRMAA surcharges adjust accordingly. End-of-life net worth, lifetime taxes, and Roth Optimizer comparisons all reflect mortality automatically.

If you had Life Expectancy set on a saved plan: your projection numbers changed starting with v6.61.2 (the engine plumbing release that preceded this UI update). The Personal tab now shows a one-time banner explaining this. Plans without Life Expectancy set continue to assume both spouses live through Plan Through Age — behavior unchanged.

The Personal tab Life Expectancy card now also renders for single filers (previously couples-only). The Survivor tab Impact Analysis remains the place to test “what if death happens at a different age than expected” — configured survivor scenarios still override the Personal tab values, as before.

v6.7 release continues in subsequent point releases: Healthcare tab rebuild with per-spouse IRMAA detail, Survivor tab repositioning, Strategy Report / Roth Optimizer recalibration. This is the user-visible kickoff.

v6.61.2
Engine plumbing for upcoming v6.7 mortality features

Internal engine change wiring primaryLifeExpectancy and spouseLifeExpectancy into the projection engine’s death-age resolution. Plans without Life Expectancy set on the Personal tab continue to behave exactly as before — both spouses are assumed alive through Plan Through Age. Plans that explicitly set Life Expectancy below Plan Through Age will see their projection reflect mortality in subsequent v6.7 UI work (next release). No user-visible behavior change in this release.

47 new tests in test-mortality-resolution.js verify the resolution logic, downstream cascades (Medicare enrollee count, IRMAA, filing status, spouse age nulling, SS survivor, pension joint50, spousal RMD rollover, expense reduction), and edge cases. All existing test suites pass at baseline.

v6.61.1
Clearer labels around Life Expectancy and Medicare totals

Clearer labels around the Life Expectancy fields on the Personal tab — these values feed the Survivor tab's analysis, not the base plan's main projection. Added a note on the Healthcare tab's Medicare summary so it's clear lifetime Medicare and IRMAA totals assume both spouses live through Plan Through Age; to model one spouse passing earlier, use the Survivor tab.

v6.61.0
Healthcare transition years

Fixed how pre-Medicare healthcare costs are pro-rated in the year you or your spouse turns 65. Previously, the transition year could under- or over-count cost depending on the household structure — for example, a household with a 7-year-younger spouse might see only one or two thousand dollars of healthcare cost in the primary's age-65 row when the correct number was much higher (because the spouse still needed ACA coverage for the rest of that year).

The new model accounts for each person's own birth month independently, so the transition year is now blended between couple-on-ACA, primary-alone, and spouse-alone phases as appropriate. Survivor years also benefit: ACA cost in the years between a spouse's death and their own Medicare age is now computed at the single rate at the survivor's actual age.

v6.60.0
Retirement marker now lands on the actual month

The orange dashed line that marks retirement on the projection chart used to snap to the start of the year — if you set retirement at age 65 in June, the line drew at age 66 instead of midway between 65 and 66. We've shifted it to reflect the month you actually set. No projection math changes; the engine has always pro-rated retirement-year earned income and savings by the month you choose. The fix applies across every chart that shows the retirement transition.

v6.59.0
Roth Optimizer: preview a strategy before applying

Click any row in the optimizer's Top 8 to expand it in place. The expanded panel shows three charts — net worth, federal tax per year, and IRMAA surcharges per year — comparing your no-conversion baseline against that strategy. Click the same row to collapse, or click a different row to swap. The charts use your real per-account returns, so what you see in the preview is what you'd get if you clicked Apply.

Apply still works exactly the same. Preview is a way to compare scenarios visually without committing to any of them.

v6.58.0
Roth Optimizer: diversity-aware top 8

The Top 8 strategies table now guarantees at least one row per strategy and bracket-target combination (Fill 12% / 22% / 24%, Smart Fill 12% / 22% / 24%, plus fixed-amount) before filling the remaining slot with the next-highest scoring candidate. Previously high-balance plans often saw eight near-identical “Fill 24%” variants on slightly different age windows, hiding meaningful alternatives at lower brackets or fixed-amount strategies. Row 0 is still the global highest-scoring strategy; diversification only affects rows 1–7. The Score column makes the underlying ranking visible.

v6.57.0
Retirement date display on the Personal tab

The Personal tab now shows the derived retirement date — month and year — directly below the Retirement Age input. Same for the spouse row when enabled. Previously the date was implicit in Current Age + Retirement Age + Month of Retirement, leaving room for ambiguity about which calendar year the engine actually treated as the retirement year. The new caption pulls them together so you can confirm your intent at a glance. Pure display addition; no engine math change.

v6.56.0
One-Time Expenses: category-aware default name

When you add a one-time expense, the default name now reflects the category you've selected instead of always reading “Home Renovation”. If you change the category later, the name updates to match — unless you've typed a custom title, in which case your edit is preserved. The category dropdown options and labels are unchanged.

v6.55.0
Today's $ deflation accuracy fix

Today's $ mode now uses different deflators for end-of-year balances and within-year cash flows. Previously the same deflator was applied to both, which slightly over-deflated cash-flow values like lifetime taxes, healthcare costs, and Roth conversion totals.

You'll see this as cash-flow tiles shifting ~1.5–3% in Today's $ mode from before. Balance tiles, Future $ mode, comparison deltas, and strategy rankings are unchanged.

v6.54.0
Return rate fixes, Maryland local tax & life expectancy

Individual account return rates are now fully independent. Previously, changing the Nominal Return on the Assumptions tab could silently overwrite rates you had set on specific accounts. That propagation is removed — each account keeps the rate you gave it. New accounts still inherit the current Nominal Return as their starting value, but changing Nominal Return later won’t reach back and overwrite them.

Monte Carlo stress simulations now scale volatility from a portfolio-weighted average of your actual account rates instead of tying to the Nominal Return slider. Shock scenarios reflect your real portfolio mix.

Maryland plans now include county/city local income tax in the projection. The rate defaults to 3.20% (Baltimore City) and is editable on the Tax tab. The Dashboard shows the combined line as “State & Local Tax” when a local rate is active.

New life expectancy fields on the Personal tab for you and your spouse. These feed into Survivor Planning defaults and will inform future planning scenarios.

MAGI restored to the Projection chart’s selectable overlays — it had dropped off in a prior update. Switching tabs now scrolls to the top of the page.

v6.53.0
Per-spouse healthcare transition, Today’s $ fix, JSON export

Per-spouse healthcare & Medicare transition. When spouses reach Medicare at different ages, RetIQ now models three distinct phases. While both are pre-Medicare, couple rates and a household-size-2 ACA benchmark apply. When the older spouse hits 65 and moves to Medicare, the younger spouse continues on your chosen coverage source at an individual rate — the Cost Summary table marks these rows with an Enrollees column showing the transition. Once both are on Medicare, pre-Medicare costs end. All six coverage sources (ACA, COBRA, Employer/Retiree, Spouse’s Plan, VA, Other) handle the split. For non-ACA sources, you can now enter an optional Individual Rate for the split-phase years; if left blank, RetIQ estimates a single rate from the couple rate. SSDI early Medicare is handled independently per spouse.

Today’s $ deflation fix. The Today’s $ toggle was deflating values one year too aggressively — Year 1 was treated as two years out instead of one. Fixed across all charts and projection tables.

JSON export. Your plan can now be exported as a JSON file from the Save menu (header ↓ button or overflow menu). Useful for backups or transferring plan data.

Income & Expenses rename. The former “Income & Spending” chart tab is now “Income & Expenses” with a guidance note explaining which cost categories are included.

Medicare now chartable on Projection tab. Medicare base cost was in the data table but missing from the chart category selector. Now available alongside IRMAA and Healthcare.

v6.52.0
HSA contributions now reduce payroll tax

If you contribute to an HSA through your employer's cafeteria plan, those contributions are exempt from Social Security and Medicare tax. Previously, the projection engine calculated payroll tax on your full salary without accounting for this exclusion — overstating FICA by up to ~$750/year depending on your contribution level. Now fixed: your projected payroll taxes will be lower and more accurate.

v6.51.0
Mixed-retirement tax accuracy fix

Fixed an issue where retirement projections could overstate taxes for households where one spouse retires while the other continues working. The working spouse's 401(k) contributions are now correctly reflected in income calculations, reducing projected tax burden during the overlap years.

v6.50.0
Guide+ withdrawal answers, dashboard expense fix, collapsible assumptions

Guide: improved answers for questions about how account withdrawals work. Dashboard: fixed expense breakdown showing inflated totals. Inputs: modeling assumptions section is now collapsible.

v6.49.0
Lees example family configuration update

Lees example family: updated account configuration to better demonstrate the Roth Optimizer workflow.

v6.48.0
Medicare and IRMAA column accuracy

The Medicare and IRMAA columns in the projection table and CSV export are now disjoint. Previously the Medicare column quietly included the IRMAA surcharge, so adding it to the IRMAA column over-stated total Medicare cost. After this release, the Medicare column shows base Part B premiums only and the IRMAA column shows the surcharge only. Their sum equals total annual Medicare cost.

In constant-dollar mode, the Medicare and IRMAA columns now adjust consistently across IRMAA tier transitions. The two columns previously used different inflation treatments, which made the totals appear to jump at tier boundaries that weren't real cost changes.

The Retirement Cash Flow chart on the Dashboard no longer over-states age-65+ deficits. It had been counting Medicare twice when totaling retirement outflows.

The Lifetime Medicare totals on the Healthcare and Survivor Center cards now correctly include both base premiums and IRMAA surcharges.

This release does not change net worth, taxes, account balances, or money-lasts-to-age. If you reload a saved plan, year-by-year totals are unchanged — only the Medicare/IRMAA split presentation has been corrected.

v6.47.0
Take more control over your RMDs

RetIQ now gives you two new options for handling Required Minimum Distributions. The first is a checkbox that says "use my RMD to fund expenses first" — for most retirees this matches reality, since the IRS is forcing the money out anyway and it lands in checking. The second is a choice for where any leftover RMD cash goes: brokerage (reinvested) or cash/HYS (kept liquid). Both controls are in Inputs → Withdrawal Strategy.

The Projection chart and table now also split the Withdrawals line into two: "spending" (what you actually live on) and "RMD reinvested" (cash that just shuffles from pre-tax to brokerage because the IRS required it). The old "Withdrawals" line was the sum of both, which made post-RMD years look more dramatic than they really were.

Existing plans keep their previous behavior unchanged. Open the new RMD Handling panel to opt in.

v6.46.2
More accurate projections for Roth 401(k) contributors

If you contribute to a Roth 401(k), your projected federal tax and Medicare premium estimates are now more accurate. Plans with Roth 401(k) contributions will show higher tax projections after this update — bringing them into alignment with how Roth 401(k) deferrals are actually treated on your W-2.

v6.46.1
Year 1 baseline note on Projection tab

Added a small note clarifying that the first projection year shows expenses at today’s values and account balances after one year of growth, with inflation compounding thereafter. The convention was always intentional but unexplained — making it explicit so the chart and table read as expected.

v6.46.0
CSV export and Expense Inflation Rate fixes

Two user-facing fixes. The CSV export Expenses column now matches the projection table (lifestyle only); Medicare and IRMAA appear as separate columns rather than bundled together. The Expense Inflation Rate input now uses general inflation when left blank, as the help text describes — previously the blank state was treated as 0%.

v6.45.0
Tax accuracy fix for senior filers

Corrected federal tax computation for filers age 65+ with income above $75,000 (single) or $150,000 (married filing jointly). Affects projection years 2026–2028. The fix produces a slightly higher federal tax estimate in those scenarios — bringing projections into alignment with IRS authority for the new senior deduction provision.

v6.44.0
More accurate tax calculations the year you turn 65

The engine now uses the IRS year-end age rule when checking eligibility for senior provisions: the additional standard deduction, the One Big Beautiful Bill Act senior bonus, HSA penalty rules at 65, and Medicare/IRMAA enrollment. Previously, projections could lag these by one year for users not born in January.

v6.43.0
Social Security FRA recalculation now modeled

If you claim Social Security before your full retirement age (FRA) and continue working, SSA may temporarily withhold part of your benefits under the earnings test. That money isn’t lost — at FRA, SSA recalculates your monthly check upward to credit the withheld months back. RetIQ now reflects this in your projection.

Note: this update covers your own retirement benefit. Survivor benefits and the spousal-top-up portion of combined benefits aren’t yet adjusted, so projections in those cases remain slightly conservative.

v6.42.0
Mega Backdoor Roth

Solo 401(k) users can now model the Mega Backdoor Roth strategy. Enable the toggle on the Self-Employed card to contribute after-tax dollars up to the remaining annual addition limit, then immediately convert to Roth. The engine auto-maximizes the headroom after your employee deferral and employer profit-share, or you can set a manual cap.

This strategy requires a Solo 401(k) plan that permits voluntary after-tax contributions and in-plan Roth conversions — not all custodians offer this feature. The after-tax amount goes directly to your Roth balance with no tax impact (assuming immediate conversion). No AGI or QBI changes from the after-tax contribution itself.

v6.41.0
SIMPLE-IRA Contributions

Self-employed users can now model SIMPLE-IRA contributions alongside Solo 401(k) and SEP-IRA. Select SIMPLE-IRA from the Retirement Plan dropdown on the Self-Employed card. The engine calculates employee deferrals (up to the $17,000 limit plus age-based catch-up) and your choice of employer contribution: a 3% dollar-for-dollar match or a 2% non-elective contribution.

All the same tax interactions apply: traditional deferrals reduce AGI and QBI, Roth deferrals are available, and S-corp owners with high FICA wages get the SECURE 2.0 §603 mandatory Roth catch-up treatment. The engine uses standard SIMPLE limits — enhanced limits for employers with 25 or fewer employees are a known simplification noted in the help text.

v6.40.0
SEP-IRA Support

Self-employed users can now choose SEP-IRA as their retirement plan. SEP-IRA contributions are employer-only — the same rates as Solo 401(k) employer contributions (20% for sole proprietors, 25% of salary for S-corps) but with no employee deferral component. This option is common for sole proprietors who want simplified retirement savings without the record-keeping of a Solo 401(k).

v6.39.0
§199A W-2 Wage and UBIA Limits

The §199A QBI deduction now accounts for W-2 wages and qualified property (UBIA) when calculating the deduction limit above the income threshold. S-corp owners automatically include their salary in the W-2 wage calculation, which means the deduction is no longer forced to $0 at high income levels. The full formula — the greater of 50% of W-2 wages or 25% of wages plus 2.5% of UBIA — now matches the statute. Businesses with additional employees or significant qualified property can access these inputs via saved plan data; a dedicated UI is planned.

v6.38.0
SECURE 2.0 §603 Roth Catch-Up

S-corp owners with FICA wages above $145,000 now have catch-up contributions automatically designated as Roth, per SECURE 2.0 §603 (effective January 2026). Your base deferral still follows your traditional/Roth choice — only the catch-up portion above the §402(g) limit is forced Roth. This does not affect sole proprietors, SMLLCs, or partnerships.

v6.37.0
S-Corporation Support

Self-employed users can now choose S-corporation as their business structure. The engine models S-corp income correctly: your reasonable salary is subject to FICA (no self-employment tax), and distributions flow as ordinary income without additional payroll tax. Solo 401(k) employer contributions use the S-corp rate of 25% of W-2 salary instead of the sole-prop 20% rate. The §199A QBI deduction properly excludes your salary from qualified business income.

Roadmap: SECURE 2.0 §603 mandatory Roth catch-up for high-earning S-corp owners (prior-year FICA wages > $145K) is planned as a follow-up. SEP-IRA, SIMPLE-IRA, defined benefit plans, and Mega Backdoor Roth contributions remain Phase 2 enhancements.

v6.36.0
State tax precision for self-employed users with QBI

State tax projections for self-employed users are now more precise. Idaho, Iowa, North Dakota, and Colorado users will see lower state tax — these states allow the federal QBI deduction to flow through to state income. California, New Jersey, and Pennsylvania users will also see lower state tax than v6.35.0; this corrects an over-count introduced last release. New York and all other states are unchanged.

v6.35.0
Three precision improvements for self-employed users

Solo 401(k) deferral capacity is now reported more accurately for self-employed users whose annual savings can't fund the full W-2 401(k) deferral target. The engine previously assumed you'd hit your full W-2 target even when your annual savings were too small, which understated how much you could still contribute to a Solo 401(k).

Self-employed users with negative qualified business income (QBI) in one year now see that loss carry forward to offset positive QBI in future years, matching IRS rules. A new field on your projection year-rows tracks the carryforward in and out.

Users in California, New Jersey, or Pennsylvania now see correct state-tax treatment when they claim the federal QBI deduction — these states don't allow it at the state level, so the engine adds it back to your state taxable income.

v6.34.0
More accurate Medicare premium estimates for retirees with active income streams

If you're already retired with active income streams (rental, consulting, annuities, etc.) and haven't filled in the prior-year MAGI fields, the engine now factors those streams into your IRMAA estimate for years 1–2 instead of treating early-year MAGI as zero.

If you've already entered prior-year MAGI in the Medicare & IRMAA card, those values continue to take precedence — this only changes behavior for users who left those fields blank.

v6.33.0
Sharper Medicare premium estimates for your first two retirement years

Medicare premium surcharges (IRMAA) are based on your tax return from 2 years prior — so the first 1–2 years of any retirement projection have to estimate something the actual lookback doesn't cover yet. If you know your MAGI from 1 and 2 years ago, you can now enter them in the Medicare & IRMAA card to refine your IRMAA projections.

Filling these new fields replaces the engine's estimate with your real numbers. Leave them blank if you'd rather use the estimate.

v6.32.0
Guide+ improvements

Some questions about retirement income from investment accounts were getting routed to the wrong canned answer (the Legacy one about leaving money to heirs). Fixed.

Also fixed an unhelpful "Cloud AI is not configured" message that showed up even when Cloud AI was configured correctly but the call had just failed. Now it distinguishes between the two cases.

v6.31.0
Strategy Report polish

Cleaned up two small inconsistencies in the Strategy Report. The Tax-Free Legacy goal now highlights the actual tax-adjusted legacy value instead of raw end-of-plan net worth — what gets shown matches what the strategy was scored on. The illustrative QLAC annual payout in suggestion cards now reads from a documented source instead of an inline magic number; the displayed amount is unchanged.

v6.30.0
Healthcare cost calibration and verdict accuracy

Refreshed Medicare IRMAA and ACA marketplace subsidy values to match the official 2026 published numbers from CMS and the IRS, and updated the QCD (Qualified Charitable Distribution) annual limit to $111,000 for 2026. Plan Health verdicts are now more accurate over long horizons — previously the cushion check could miss thin plans because it didn't fully account for inflation.

v6.29.0
Faster Roth conversion optimizer

Made the Roth conversion optimizer noticeably faster. The optimizer searches over many candidate conversion schedules to find the one that minimizes lifetime taxes — it was running a full tax calculation loop for each candidate when a faster equivalent was available. Same recommendation, less waiting.

Also tidied up some platform-detection code that became redundant after last release's access-check fix. No user-visible change.

v6.28.0
Native app access check hardened

Fixed an access check on iOS and macOS. Some premium features could be opened on the native apps without an active purchase. The check now verifies your purchase status the same way on every platform.

The JSON export option now uses the same access check as the other export formats — it had been missing one. If you've already purchased the full version, none of this changes what you see.

v6.27.0
2026 Social Security values + refreshed Model Notes

Updated Social Security calculations to use the 2026 statutory values announced by SSA in October 2025. PIA bend points and earnings-test limits now reflect current-year amounts. For users projecting Social Security benefits via earnings-history estimation, this corrects an understatement of about 1.5% in projected benefits. If you've already provided your PIA from your SSA statement, this change doesn't affect your projection.

Refreshed the Model Notes shown in Inputs and the Strategy Report. Notes now affirmatively describe how federal tax brackets, standard deduction, capital gains breakpoints, QBI thresholds, and IRMAA tier amounts are projected forward from 2026 base values year-over-year. Added a note covering the OBBB §70103 senior deduction (available 2025-2028, sunsets December 31, 2028 unless extended). Fixed three stale year references in input field help text — IRMAA bracket label, earnings-test prose, and QCD limit (now $111,000 per IRS Notice 2025-67).

v6.26.0
More accurate Roth conversion and Tax-Aware Drawdown recommendations near the senior-deduction phase-out

Improved Roth conversion and Tax-Aware Drawdown recommendations for users in the new senior-deduction phase-out range. The optimizer now uses the same income definition as the underlying tax calculation when sizing conversions or withdrawals, so its recommendations more accurately hit the bracket targets it claims.

Affects users age 65 or older with income near the phase-out band. Outside that band, recommendations are unchanged.

v6.25.0
Social Security wage base projections updated to SSA Trustees intermediate growth

Updated the Social Security wage base projection to match the latest SSA Trustees Report intermediate growth assumption (3.6% per year, up from 3.0%). This affects retirement projections that reach the wage base cap, providing more accurate Social Security benefit estimates and FICA / self-employment tax projections for high earners over long horizons.

The change also tracks the annual Social Security earnings test limits, which grow at the same rate.

v6.24.0
Medicare IRMAA tier thresholds adjust for inflation

The Medicare IRMAA income brackets that determine your Part B and Part D surcharges now adjust for inflation across your plan's projection years. Previously, the brackets were held at 2026 values for the life of your plan, which slightly overstated your projected Medicare costs in later years. Plans projecting income near the IRMAA thresholds may now show somewhat lower projected Medicare premiums in later years. The top tier ($750K MFJ / $500K Single) is statutorily frozen until 2028, then begins indexing — engine reflects this correctly.

v6.23.0
Tax bracket and deduction indexing across projection years

Federal income tax brackets, standard deduction, senior addition, OBBB §70103 senior deduction, capital gains breakpoints, and QBI thresholds now adjust for inflation across your plan's projection years. Previously these were held at 2026 values for the life of your plan, which meant late-year projections overstated your tax bill. Plans that extend more than a few years into the future may now show somewhat lower projected taxes in the later years.

v6.22.0
Tax accuracy fixes for IRMAA and ACA

Two related accuracy fixes for users in specific situations. If you're still working with 401(k) contributions, the engine no longer overstates your income when checking your future Medicare premium tier. If you're collecting Social Security and using ACA marketplace coverage before Medicare, your projected ACA subsidy is now correctly calculated against the income definition the IRS actually uses for that program. Plan results may shift slightly for these scenarios; everyone else is unaffected.

v6.21.2
IRA catch-up updated to $1,100 for 2026

Updated the IRA catch-up contribution limit (the extra you can contribute starting at age 50) from $1,000 to $1,100 to match the 2026 IRS-published amount. The HSA over-55 catch-up stays at $1,000 (not indexed to inflation by statute).

v6.21.1
Catch-up contribution caps

Fixed a small projection issue where IRA catch-up contributions (the extra $1,000 you can contribute starting at age 50) and HSA catch-up contributions (the extra $1,000 if you're 55 or older) were being inflated each year. Both amounts are set by statute and don't change with inflation. The correction mostly affects retirement-prep plans 10+ years out, where projected contribution caps are now slightly lower (and accurate).

v6.21.0
Social Security and self-employment tax projections

Multi-decade plans now project the Social Security wage base forward each year using the annual indexing rate, instead of holding it flat at the current-year value. This makes the FICA and self-employment tax cap track inflation across long retirement plans, which mostly matters for self-employed retirees and high-earners with W-2 wages above the cap.

Also fixed an edge case where Additional Medicare tax (the 0.9% surtax for high-income households) wasn't being applied during retirement years for self-employed households on the TAD strategy branch. The total tax bill in those years is slightly higher and more accurate.

v6.20.0
State-tax accuracy and Social Security guidance

Maryland's local income tax (county and Baltimore City rates of 2.25% to 3.30%) is now factored into your projection. Default rate is 3.30%, the statutory cap matching Baltimore City and several counties. If your county uses a different rate, you can override it in the State for Tax Purposes section.

New Jersey's pension and IRA exclusion now correctly phases out across four tiers based on your gross income, with separate maximum values for joint filers ($100K) and single filers ($75K). Previously the engine applied a flat exclusion regardless of income or filing status, which over-excluded most NJ retirees and entirely missed the cliff at $150K.

If you're under 62 and using the average-income-based estimate for Social Security, the calculator now includes a brief note explaining that this estimate may understate your benefit by 10 to 15 percent, and points you to your SSA statement for a more accurate projection.

v6.19.0
Social Security COLA accuracy fix

Fixed a long-running bug where projected Social Security benefits didn't reflect cost-of-living adjustments between today and your planned claim age. If you're 62 and planning to claim at 67, your statement-PIA now grows with your assumed COLA over those 5 years before claim, then continues annually thereafter — matching how SSA actually calculates benefits.

Users with 5+ years between today and claim see meaningfully higher projected lifetime SS. The largest corrections are for users delaying claim past full retirement age. Already-collecting users see no change — their entered current monthly already reflects past COLAs.

v6.18.20
Phase C engine accuracy

Several federal tax calculations have been tightened. You'll see slightly different numbers if you have self-employment income above the IRS Additional Medicare Tax threshold ($200K single / $250K joint), ordinary (non-qualified) dividends from a taxable brokerage account, or a spouse claiming Social Security before their full retirement age. Plans without those features won't show changes.

The Medicare cost inflation rate is now a user-configurable input on the Healthcare tab (default still 5%/year), so you can stress-test against your own assumptions about Medicare premium growth.

v6.18.19
Survivor Plan now shown on every tab

When a Survivor Plan is active, a banner now appears at the top of every tab so you always know which mode you're in. The banner includes an Exit button. Previously the active state was only indicated on the Adopt Plan sub-tab, which made it possible to forget you were in single-person mode.

Survivor benefit now pays automatically once the survivor reaches Full Retirement Age, regardless of the Survivor SS Claim Age setting.

v6.18.18
ACA subsidy fix for early-retirement first year

The Pre-Medicare Healthcare projection underreported the ACA premium tax credit in the first year for retirees who fund their living expenses primarily from pre-tax withdrawals before Social Security or pension income begins. In that scenario the first-year subsidy could show as $0 even when the displayed MAGI was clearly within the eligible range. Subsequent years calculated correctly. The first-year estimate now reflects the same income proxy used in the input-screen subsidy preview, so the subsidy shown on the input screen matches what the projection delivers from year one.

v6.18.17
Dashboard: still-working spouse income on retirement-view card

For households where one spouse has retired but the other is still employed, the Dashboard’s “This Year’s Retirement Plan” card now shows the working spouse’s earned income as a row in the Inflows section. Previously the retirement-view card had no earned-income line at all, so a working spouse’s salary was invisible despite being correctly taxed under the hood. Rows are labeled “Your Income (still working)” or “Spouse Income (still working)” to disambiguate from the working-view card.

The Net Annual Cash Flow bar for retired plans now correctly includes the working spouse’s wages as external income. If your plan has a retired primary plus a working spouse whose salary covers most retirement expenses, you may see this bar shift from amber (portfolio drain) to green (surplus). The previous behavior was a gap, not a feature — W-2 wages from a working spouse are external income, just like Social Security or pension.

Plans where both spouses are retired, solo plans, and plans where the retired person has no working spouse are unaffected.

v6.18.16
Hotfix: blank Dashboard for dual-spouse plans with spouse-owned pre-tax accounts

Users with both spouses enabled AND at least one pre-tax account marked as spouse-owned would see a blank Dashboard tab whenever the engine output triggered the dual-owner RMD badge code path. Other tabs (Inputs, Projection, Monte Carlo, etc.) worked normally; only Dashboard rendering was affected. Engine math was unaffected throughout — this was purely a UI render-time crash.

Cause: a v6.18.14 dashboard change referenced a local variable rmdAge that didn't exist in the renderDashboard function's scope. The variable was declared in a sibling helper function further up the file, and the v6.18.14 brief assumed scope membership based on lexical presence rather than enclosing-function membership. JavaScript threw ReferenceError: rmdAge is not defined the first time the dual-owner badge code executed, aborting the dashboard render mid-write and leaving a blank tab.

Fix: declared rmdAge at the top of renderDashboard's scope using the same expression the sibling helper uses. One-line addition. Also flipped a related || to ?? in the sibling helper to match the project's defensive-coercion convention (consistent with the v6.17.x coercion sweep).

v6.18.15
Cleaner Projection table Expenses, Medicare, and IRMAA columns

The Expenses, Medicare, and IRMAA columns on the year-by-year Projection table previously included one another — Expenses silently included Medicare premiums and IRMAA surcharges, and the Medicare column duplicated the IRMAA portion. Adding all three together produced a number much larger than reality. Now the columns decompose cleanly: Expenses shows your non-Medicare retirement spending, Medicare shows the base premium only, and IRMAA shows the surcharge. Adding the three together matches the engine's full expense total. The chart line for Expenses uses the same decomposition so chart and table agree.

v6.18.14
RMD card now reflects both spouses; new inherited-distributions card; RMD badge added to the Dashboard

The RMD information card on the Accounts tab now shows the right thing for households where both spouses have their own pre-tax accounts — it surfaces both ages, both first-year estimates, and orders them by who reaches RMD age first. Single-owner households see the same card as before.

A new inherited-distributions card appears below the RMD card when you have an inherited IRA. It shows the inherited balance and the SECURE Act 10-year deadline. Inherited distributions are separate from your own RMDs and the card is labeled accordingly so the two never get confused.

Finally, an RMD badge has been added to the Dashboard's Active Strategies row, alongside Roth Conversions, Tax-Aware Drawdown, Social Security, and Inherited. It shows your lifetime RMD total and when RMDs start.

v6.18.13
Two UI fixes from user feedback

The Dashboard "Active Strategies" Social Security badge displayed the FRA monthly amount times twelve, ignoring early/late claim-age adjustments, ignoring COLA accrual, and ignoring the Today's $ / Future $ toggle — so the badge value didn't match what the projection actually used. The fix pulls the badge value from the first projection year where Social Security is paid, deflated per year. All engine adjustments (ssaAdjustPIA early/late credits, COLA, earnings-test withholding, SSDI auto-conversion, "already collecting") are now reflected automatically, and the badge honors the dollar toggle the same way the sibling Roth Conversion and Tax-Aware Drawdown badges already did. The badge age also now reflects SSDI's FRA-conversion override when active, matching the Inputs → SS tab.

The Charitable Giving Annual Amount field rejected $0 once any other value had been entered — typing zero stored zero correctly, but the next render fell back to the default $10,000 because of a ||-vs-?? coercion bug. Now respects an explicit zero. Same pattern that v6.16/v6.17.5/v6.17.6 swept across roughly 30 sites; this site was missed.

Engine math and state management are unchanged in both fixes — both bugs lived purely in the render layer.

v6.18.12
Per-account post-2019 inherited IRA distributions

Two bugs fixed in the SECURE Act 10-year forced-distribution path. Multiple post-2019 inherited IRAs with different inheritedYear values previously shared a single deadline (the earliest), so an account inherited in 2026 alongside one inherited in 2021 was forced to deplete on the 2031 deadline instead of 2036 — reported by a user testing v6.18.10. Independently, inherited Roth distributionTiming used .find() on the accounts array, applying the first account's regime to all pooled inherited Roth balances; now respected per-account.

The post-2019 distribution math now mirrors the per-account loop already in place for pre-2020 stretch IRAs. Pooled inheritedPreTax / inheritedRoth are kept as derived sums for downstream consumers (growth, net worth, year-record); invariant pool == sum(working copies) maintained through distribution, growth, and one-time-expense paths.

Authority: IRC §401(a)(9)(H)(i) (per-decedent 10-year window); IRS T.D. 10001 (July 19, 2024) (no annual RMD requirement on inherited Roth during the window); IRC §408A(c)(5) (beneficiary-discretionary timing). 3 new validation tests under the “Inherited Per-Account” category lock the per-account schedule, the depletion-order invariant, and per-account regime selection on inherited Roth.

Also: minor test arg-order tidy in test-validation.js (one assertion in the new Inherited Per-Account category had expected and actual swapped — passed correctly because the assertion is symmetric, but reordered to match the rest of the suite for readability).

v6.18.11
QLAC per-spouse modeling

Each spouse can now hold their own QLAC, tied to their own pre-tax balance and their own RMDs. A married couple can model up to $420,000 in combined QLACs ($210,000 each in 2026 per IRS Notice 2025-67). When you have a spouse enabled with at least one pre-tax account marked as theirs (in Accounts), a separate Spouse QLAC card appears in Inputs → Pension below the primary QLAC card.

This is also a correctness fix. Previously, a single household-level QLAC purchase drew proportionally from both spouses' pre-tax shares. Under Treas. Reg. §1.401(a)(9)-6, a QLAC reduces only its owner's IRA balance and only that owner's RMD. The engine now attributes purchase and payout to the correct owner. For a couple with equal pre-tax balances, this means a $200K primary QLAC fully reduces primary's RMD instead of half-reducing each spouse's RMD.

The Strategy Report Card now suggests up to three QLAC alternatives where appropriate: Primary QLAC (when primary's pre-tax balance exceeds $300K), Spouse QLAC (when spouse's exceeds $300K), and Dual QLAC (when both qualify and neither is currently enabled). The "No QLAC" alternative considers whichever combination is currently active.

Engine year-output adds four per-owner fields: qlacBalancePrimary, qlacBalanceSpouse, qlacPayoutPrimary, qlacPayoutSpouse. The existing qlacBalance and qlacPayout fields keep their household-sum meaning — charts, dashboard, CSV export, and native iOS/macOS continue to work without modification. Six new validation tests on a spouse-enabled fixture cover dual-disabled, primary-only attribution, dual-purchase totals, the backward-compatibility sum invariant, and spouse-age-driven payout timing.

Sources: IRC §401(a)(9)(F); Treas. Reg. §1.401(a)(9)-6 Q&A-17(b); SECURE 2.0 Act §202; IRS Notice 2025-67; Form 1098-Q.

v6.18.10
QLAC purchase cap updated to 2026 limit ($210,000)

The QLAC purchase cap moves from the SECURE 2.0 base of $200,000 to the 2026 inflation-adjusted limit of $210,000. The cap is now sourced from REGS.retirement_accounts.qlac_limit — the same regulatory data layer that holds federal brackets, contribution limits, and IRMAA thresholds — so future inflation adjustments land via the regulatory data feed without code changes. Updated in the engine, Inputs → Pension & QLAC card, Strategy Report alternative, manual, features page, and AI guide. Sourced from IRS Notice 2025-67; SECURE 2.0 Act §202; Treas. Reg. §1.401(a)(9)-6.

Two new validation tests cover the constant value and the engine's enforcement of the cap when a user requests more than the limit.

This release does not change the per-individual nature of the cap. RetIQ currently models a single household-level QLAC; a future release will add per-spouse QLAC modeling so married couples can reflect the full $420,000 of combined eligibility ($210,000 each).

Separately, repaired the QLAC test fixture in test-validation.js. The previous minimal fixture was missing several engine-required fields (birthYear, nominalReturn, SS config, etc.), which caused runProjection() to return NaN throughout the projection. Three of the four existing QLAC tests had been passing for the wrong reason — their boolean-ternary outputs fell through to 0, and the integer tolerance of 1 absorbed the failure. Fixture repaired to a complete params object; all four tests now pass against real numeric output. No engine changes; the assertions were correct, only the inputs feeding them were broken.

v6.18.9
Today's $ toggle: inline rate is now read-only and links to Assumptions

The small % infl. input on the Today's $ toggle looked editable but discarded any value typed into it — both render() and renderDollarToggle() reassigned the displayed rate from state.params.inflation on every redraw, overwriting any inline edit before it could take effect.

The inline input is now a read-only, clickable label that jumps to Inputs → Assumptions and scrolls the Inflation Rate field into view. Single source of truth: change the rate once, in Assumptions, and the toggle reflects it everywhere — matching what the iOS and macOS apps already do. Allowing a divergent display rate would produce mathematically meaningless numbers (deflating nominal projections by a rate that doesn't equal the engine's inflation yields neither today's dollars nor future dollars), so removing the editable surface is also the mathematically correct choice.

New regression tests in test-ui-paths.js lock in the read-only markup and the navigation helper export.

v6.18.8
Dashboard — per-spouse income rows

The "This Year" card on the dashboard now shows Your Income and Spouse Income as separate rows when a spouse is enabled, mirroring the labels on the Inputs tab. Solo plans continue to show a single Employment Income row.

Engine: new primaryEarned and spouseEarned fields on the year-output object. Additive only — no math changes. The existing earned field is unchanged and still equals primaryEarned + spouseEarned. Three new validation tests assert field presence and the sum invariant.

v6.18.7
Healthcare tab card order fix

v6.18.6 missed a card when merging Medicare into Healthcare. The Pre-Medicare Coverage Cost Summary — which shows gap length, total net cost, and a year-by-year cost table for the pre-Medicare years — was sitting at the bottom of the Healthcare tab, separated from its config card by Medicare and LTC. Moved it to immediately follow Pre-Medicare Healthcare. New order: Pre-Medicare Healthcare config → its Cost Summary → Medicare & IRMAA → Long-Term Care. Pre-Medicare config and its derived display now sit together; Medicare and LTC come after as the later phases.

v6.18.6
Healthcare and Medicare combined into one tab

The Inputs → Medicare tab had no inputs — just an IRMAA bracket table, lifetime stats, and a chart, all computed from the projection. A user pointed out the disconnect: the tab name promised inputs, the page delivered display. The fix is structural rather than cosmetic: combine Healthcare and Medicare into a single Healthcare tab with three cards stacked vertically — Pre-Medicare Healthcare, Medicare & IRMAA, and Long-Term Care. Reading order matches age progression (before 65, 65+, typically 80+).

The web sub-nav drops from 14 tabs to 13. The Medicare card content is unchanged — same bracket table, same chart, same lifetime stats — just relocated. If a saved plan was sitting on the Medicare tab when it last loaded, the next render quietly redirects to Healthcare so nothing appears broken. Plan Health levers and AI guide references that pointed at the old Medicare tab now point at Healthcare.

This brings the web app's IA in line with the iOS native app, which already groups Pre-Medicare and Medicare under a single Healthcare disclosure.

v6.18.5
Peak Net Worth and Peak RMD now correct in Today's $

A user diagnosed this one cleanly: "the peak is identified in future $s, and then displayed (accurately) in both toggle settings. That can lead to the scenario where the peak in future $s (converted to current $s) is less than the current value (current $s), so the display is off." Exactly right.

The Snapshot was identifying the peak year by largest nominal Net Worth, then deflating that single value when the Today's $ toggle was on. For retirement plans where Net Worth grows nominally for a decade or two before declining, the nominal-peak year is far enough in the future that its deflated value is smaller than year 0 (Current Net Worth). One user saw $4.0M Current and $2.9M Peak in Today's $ — mathematically impossible when computed correctly, since year 0 is always one of the candidates for "max."

Fix: deflate each year individually first, then take the max. The maximum of the per-year deflated values can never be less than year 0's value. Matches the v6.18 Projection Table totals fix — same pattern, single-statistic version.

Same fix applies to Peak RMD in the Active Strategies card and to the Plan Health levers helper. The dual-owner Peak RMD sub-line now reads per-owner amounts from the year where the deflated total RMD peaks, so the sub-line reconciles with the main value. 11 new regression tests in test-ui-paths.js reproduce the reported scenario and lock the corrected behavior.

Future $ display is unchanged. For retirement plans declining in real terms (the common case), Peak Today's $ will typically equal Current Today's $ — today is your peak purchasing-power year, before withdrawals erode it.

v6.18.4
Honest stress test labels and std dev guidance

The Monte Carlo Stress Test was advertised as "worse than historical" but at default settings (6% return std dev, fat-tailed distribution) it was actually gentler than Historical replay — because Historical inherits the actual ~19% S&P 500 variance from 1928–2024 data, while Stress Test's variance is governed by the std dev parameter you set. Six percent fat-tailed is dominated by Historical's nineteen percent intrinsic variance, regardless of fat tails.

Three honesty fixes:

The default values (6% / 1.5%) are unchanged so saved plans don't shift. Users who want a real stress test now have correct guidance to set honest values.

Engine math is unchanged. Validation tests unaffected.

v6.18.3
Pensions and QLACs honor fractional start ages

If you set a pension's start age to a fractional value like 65.5, the engine was using integer-floor activation: at age 65 the comparison 65 >= 65.5 is false, so the pension was skipped entirely. At age 66 it activated with the full annual amount. The user who reported this had a $36K pension starting at 65.5 and lost six months of income (~$18K) from the projection.

Now the engine activates the pension when the user's age year overlaps the start age and pays a prorated amount for the first partial year. Setting startAge: 65.5 with a $36K annual amount pays $18K in the age-65 fiscal year, then $36K every year after. Same fix applies to the spouse pension and to QLAC payout start age. Integer start ages (the most common case) produce identical results to before — this is a backward-compatible bug fix.

Tax treatment: pension payments are gross income in the year received per IRC §61(a)(11), and QLAC payouts are taxable as ordinary income per IRC §401(a)(9)(F) and Treas. Reg. §1.401(a)(9)-6 Q&A-17 — both fully consistent with reporting the prorated cash actually received in a partial year. taxablePercent and survivorBenefit ratios apply post-proration; the math is associative.

11 new regression tests in test-validation.js covering integer baseline, fractional 0.25/0.5/0.75 cases, pre-activation zero, lifetime invariant, spouse pension proration, COLA compounding over fractional years, and taxablePercent post-proration application. Engine validation total goes from 519 to 530, all green.

v6.18.2
Honest Medicare display + correct Expenses guidance

The engine adds Medicare premiums and IRMAA surcharges to expenses automatically once you reach Medicare age (CMS bills the beneficiary, so it's a real cash outflow). Three places didn't reflect that consistently:

Engine math is unchanged. The retirement expenses field continues to mean "your non-medical retirement spending today, in today's dollars" — which is what most users were intending to enter anyway. If you previously included an estimate of Medicare premiums in your annual expense figure (per the old guidance), your projection was overstating costs by roughly that amount each year past 65; you should now subtract it out for an accurate model.

v6.18.1
Today's $ toggle now applies to Scenarios, Monte Carlo, and Medicare charts

Three charts were ignoring the dollar toggle and showing only Future $ values regardless of the user's selection: the Scenarios comparison chart, the Monte Carlo fan chart and statistics (Median Final, 10th/90th percentile), and the Medicare Costs by Age chart on the Medicare input tab. The status bars above the Scenarios chart already deflated correctly — only the chart itself was wrong — so users saw a numeric mismatch between the stat row and the chart. Monte Carlo was the most confusing: nothing updated when toggling unless the user re-ran the simulation.

Root cause: each chart's data construction fed buildChart raw nominal values from the projection without applying the per-year deflate() helper. Now they follow the dashboard's net-worth-chart convention: deflate each year individually before passing to the chart. Same pattern as the v6.18 fix to the projection table totals row.

Audit-discovered: the same bug existed in 11 additional charts — Bear Market stress test, Healthcare Inflation stress test, Relocation comparison, three Survivor Center charts (NW/SS/Tax), four Roth Conversion Impact Analysis charts (Advantage, Pre-Tax/Roth balance comparisons, Annual Conversions), and three Roth Conversion Optimizer charts (Cumulative Tax, Conversion Advantage, Account Composition). All 14 chart sites are now fixed.

4 new regression tests in test-ui-paths.js covering the chart-data deflation convention. The deploy gate's per-year-deflation pattern grep continues to enforce consistency across the codebase.

v6.18
Projection Table totals row now uses per-year deflation

The year-by-year Projection Table's totals row was computing each currency column total by summing nominal values across all years, then deflating that single total once at the midpoint year. That works for uniformly-distributed streams but is wrong for anything concentrated early or late in retirement. Roth conversions cluster in early retirement — per-year deflation barely shrinks them, midpoint deflation over-deflates by ~10 years' worth, understating the total. RMDs and late-life healthcare cluster late — opposite direction, overstating. Now matches the dashboard's Active Strategies badge convention: deflate each year individually, then sum.

If you were comparing the dashboard's "Roth Conv" badge in Today's $ against the projection table's "Roth Conv" totals row, you'd see different numbers (one user reported $1.1M vs $764K for the same plan). Future $ totals were unaffected because no deflation is applied in nominal mode. After this release, the badge and the table agree.

Same fix applies to every other currency column in the totals row — Tax, RMD, Withdrawals, IRMAA, Medicare, ACA, Charity, Capital Gains, Cash Interest. All now match the dashboard's per-year deflation convention. 4 new regression tests in test-ui-paths.js.

Behavioral note: anyone running side-by-side Today's $ comparisons between the dashboard and the table will now see consistent numbers. Anyone who only used the table totals will see slightly different numbers depending on the stream's distribution — the new numbers are correct, the old ones were biased.

v6.17.6
Final coercion sweep: 0% honored for employer match, SS trust fund, cash events, Roth %

Closing chapter on the ||-vs-?? bug pattern. v6.17.4 fixed the dollar-toggle. v6.17.5 swept the next 23 sites. This release fixes the last 4 field families I knew about: employer match override (custom percent and cap), SS Trust Fund reduction (the headline scenario where users model "what if Congress doesn't act"), cash event net percent (sale, inheritance, business-sale modeling), and Roth conversion percentage-of-balance.

The most user-impactful fix here is SS Trust Fund: setting reduction percent to 0% (meaning "Congress acts, full benefits paid") was being silently coerced to 20%. Anyone running side-by-side comparisons of the no-action vs. action scenarios was getting the wrong baseline.

Pattern category is now retired across the codebase. The deploy-gate regression tests and post-deploy curl checks lock the behavior. Any future || regression at any of the 30+ sites we've fixed since v6.17.4 will fail the gate.

v6.17.5
Sweep: 0% honored for every numeric assumption

Continuation of v6.17.4. The audit there flagged ~15 additional sites with the same X || N coercion pattern across the codebase. After review, every one of them was a real bug — in this codebase, every numeric user input has a meaningful 0 case. This release converts all of them to ?? so explicit 0 is honored.

Field families fixed: nominal return (4 sites — Strategy Report, PDF export, Survivor Center, Plan Health), healthcare inflation chains (Pre-Medicare and Medicare), LTC inflation, survivor expense reduction, expense phase multipliers (later/late retirement), and Guyton-Klinger guardrails (lower, upper, adjustment).

Behavioral note: if you had any plan with one of these fields explicitly set to 0% (e.g., a "stable healthcare costs" stress scenario, or a "guardrails do nothing" experiment), your projection and Today's $ display will now actually reflect the 0% you typed. Pre-fix, those plans were silently running at the field's default rate.

11 new regression tests in test-ui-paths.js covering every fixed field family. The bug pattern is now closed across the codebase: a future X || N regression at any of these sites would fail the deploy gate.

v6.17.4
Fix: Inflation 0% now honored by Today's $ toggle

Setting Assumptions → Inflation to 0% had no effect on the dollar-toggle: the top-line rate display kept reading 3% (or whatever the previous value was), and the inline rate input on the toggle accepted edits but didn't stick after the next render. The pension display in Today's $ also continued to degrade over time as if inflation were still 3%. Two lines in the dollar-toggle and main render functions used JavaScript's || operator to fall back when the inflation field was missing — but 0 || 3 === 3 in JavaScript, so an explicit user-entered 0 was silently coerced to the default. Both lines now use ?? (nullish coalescing), which only triggers the fallback for null or undefined — not for an intentional 0.

This is the same coercion pattern that affected SS COLA before v6.16 (where setting SS COLA = 0% silently ran 2%). When that fix shipped, I patched six engine sites but didn't audit the rest of the codebase. This release runs a comprehensive audit and closes the pattern across the dollar-toggle. New regression tests in test-ui-paths.js lock the behavior so a future || regression at either site would fail the deploy gate.

Behavioral note: any saved plan with inflation: 0 will now actually project at 0% inflation. Pre-fix, those plans were silently running at 3% deflation in the Today's $ display (Future $ was unaffected). If you had a plan where you'd set 0% to test a "real-dollar" scenario, your Today's $ numbers will now match Future $ values exactly, which is the correct behavior.

v6.17.3
Cash Interest income now visible on dashboard and projection

Interest from cash, HYS, money market, CD, and short-term Treasury holdings — the cashInterest field the engine has always produced — was missing from the dashboard’s Inflows section and the year-by-year Projection Table. The engine routed it correctly through every tax pipeline (NIIT, ordinary income, MAGI, Social Security provisional), but a user with $200K in a money-market account at 2% yield wouldn’t see the $4,000/year of interest anywhere unless they manually checked the chart-overlay “Cash Interest Income” box. Now it appears as a row on the Retirement-tab and Working-tab Income sections, and as a Cash Int column in the Projection Table (auto-hides at zero). Net Annual Cash Flow bar on the Retirement tab includes it in the inflows side.

No engine math change. Existing validation tests cover the underlying calculation and tax routing — this release surfaces the number to UI.

v6.17.2
Fix: phantom $6K “Other Income” for empty-portfolio plans

Long-running issue where the projection’s OTHER INC column showed a flat $6,000/year on plans that had no income inputs and no portfolio — particularly visible to users who were testing the app with a zeroed-out scenario. Cause: the legacy additionalIncome field defaulted to $6,000 in fresh plans, the web UI was replaced by Income Streams in v4.x and never exposed an input for it, and the engine’s backward-compatibility shim was virtualizing the legacy field even on plans that had already been migrated to streams (i.e., had incomeStreams: []). The combination produced a stale $6K floor that no UI control could clear.

Three-layer fix. The seed default is $0, so new plans never reproduce the state. State migration zeros stale additionalIncome on any plan that already has an incomeStreams array (legitimate pre-v4.x plans, where incomeStreams is genuinely undefined, are untouched). The engine’s legacy virtualization shim now requires incomeStreams === undefined to fire, so the phantom can’t return through any load path even if a saved plan slips past migration.

Three new validation tests cover the stuck state, legacy passthrough, and stream precedence. Reported by users running zero-input scenarios in v6.16.x; an earlier attempt today shipped a partial fix that didn’t address the engine-side back-fill.

v6.17.1
Fix: Annual Benefit summary card now reflects current benefit when already collecting

If you had “I’m already collecting Social Security” toggled on, the green “Annual Benefit” summary card under each SS card was sourcing its number from the legacy SSA-statement / income-based path and ignoring your entered current monthly benefit. On the spouse side this showed as $0 when no legacy fields were filled in; on the primary side it showed slightly off (off by whatever drift was in the leftover manual entry). Now both cards read directly from the entered current benefit when already-collecting is on, and the card label drops “at Claim Age X” since it doesn’t apply.

The reduction-percentage and Earnings Test warnings that sit beneath the summary card are also suppressed in already-collecting mode — both are forward-looking warnings about claiming decisions, irrelevant once you’ve already claimed.

No engine change. The projection itself was already correct (v6.16 wired the engine path); this fix only addresses the input-tab summary display.

v6.17
Multiple pensions per person

You can now model more than one pension per person on the Pension tab. Use the “+ Add Pension” button to add a second (or third, or more) pension for yourself or your spouse — useful for households where one person has benefits from multiple former employers, or military retirement plus a civilian pension. Each entry has its own start age, COLA, survivor option, and taxable percentage. The engine sums all enabled entries each year.

The single-pension input cards from prior versions are still there as the first entry; they auto-migrated when you opened the app under v6.16.x. Saved plans load unchanged.

Manual updated. Engine math is unchanged from v6.16.x — the underlying array structure was already in place; this release exposes it in the UI.

v6.16.2
Pension data structure refactor (internal)

The engine and state now store pensions as an array (pensions[]) instead of two scalar params (pension and spousePension). Saved plans auto-migrate on load. No user-visible change — the input UI still shows the same Your Pension and Spouse Pension cards. This is preparation work for a future update that will let you model multiple pensions per spouse (military + civilian, multiple former employers, etc.).

5 new validation tests cover the migration shim, two-pension-per-spouse summation, staggered start ages, and mixed-owner pairs. All existing pension tests pass unchanged on the new array-backed engine.

v6.16.1
Manual update for “Already collecting” SS mode

Documentation pass following v6.16. The Social Security sections of manual.html and the in-app iOS manual now describe the third entry mode (“Already collecting”) alongside the existing income-based estimate and SSA-statement-at-FRA modes, and call out that the entered amount is gross of Medicare Part B premium deduction in all three modes. No engine or UI logic changes.

v6.16
“Already collecting” mode for Social Security

You can now tell RetIQ that you (or your spouse) are already collecting Social Security and enter your current monthly benefit directly, rather than back-solving for the FRA amount. The new toggle sits on the SS card — check it, enter what you actually receive each month, and the engine uses that figure as your starting SS income with COLA accruing forward from your current age. Independent toggle for primary and spouse, so households where only one person has claimed are handled cleanly.

For households with a non-working or low-earning spouse, RetIQ still needs an approximate PIA to compute the spousal floor and survivor benefits. The new ssReverseAdjustPIA helper recovers that PIA by reversing the SSA early/late adjustment formula (POMS RS 00615.301 and RS 00615.304) using the age you started collecting. The recovered figure is in current dollars rather than original-FRA dollars — past COLAs are baked in — which means survivor and spousal calculations are slightly approximate for households that have been collecting for many years. The error is small in practice; precision back-out of historical COLAs is a future enhancement.

Help text for the existing FRA-amount field also clarifies that the entered value is the gross benefit, before any Medicare Part B premium deduction. RetIQ models Medicare costs separately on the expense side, so the gross figure (Box 5 of your SSA-1099) is what the engine needs.

Behavior change for plans with COLA = 0%. Six SS COLA sites in the engine were silently coercing an explicit 0% COLA to 2% (because 0 || 2 === 2 in JavaScript). All six now use ?? 2, so 0% means 0%. If you had a saved plan with SS COLA set to 0, your projection's Social Security income line will now actually stay flat instead of growing 2%/year. The fix is correct; the prior behavior was a latent bug.

27 new tests in test-already-collecting-ss.js covering reverse-PIA round-trips, primary already-collecting integration, spousal floor with recovered PIA, spouse-only-collecting cases, both-spouses-collecting cases, and a backwards-compatibility check against the existing spousal-SS suite. 5 additional unit tests in test-validation.js for the new helper. All four suites green: test-validation.js, test-spousal-ss.js, test-self-employed.js, test-already-collecting-ss.js.

Authority: 42 U.S.C. §402(q) (early-claiming reduction); 42 U.S.C. §402(w) (delayed retirement credits); SSA POMS RS 00615.301, RS 00615.304. Medicare gross/net basis: 42 U.S.C. §1395s; SSA POMS GN 02410.180; IRS Pub. 915 (gross benefit on SSA-1099 Box 5).

v6.15.4
Two bug fixes: phantom Other Income and stale brokerage dividend tracking

Two engine fixes reported by a customer.

1. Phantom $6k Other Income. A legacy additionalIncome field in the seed plan default was carrying forward into newly-created plans even after the income-streams replacement shipped in v4.x. The migration that was supposed to convert the legacy field into a real, editable income stream was gated on incomeStreams === undefined — so plans that already had an empty incomeStreams: [] array (the v4.x default) skipped the migration entirely, and the engine's backward-compat block kept injecting a phantom $6k/yr ordinary-income stream every projection year. Affected anyone whose plan had been initialized between v4.x and v6.15.3 with the seed default. Fix: decouple the income-streams init from the legacy migration so both run independently, zero the legacy field idempotently after migration, and zero the seed default. Existing plans self-heal on app load.

2. Brokerage dividend yield computed off the static input balance. The per-account dividend yield loop was reading acct.balance — the year-0 input — on every projection year. Result: dividend income stayed flat forever even as the brokerage compounded or was drawn down. Customer described it precisely: “even though my brokerage account grows in the projection, the income included in Other Income is flat.” Fix: each brokerage account holds a constant share of the pooled balance (share = acct.balance / totalStartingBrokerage, computed once); per-year dividend = share × taxableInv × yield ÷ 100. Pool growth and pool withdrawals now propagate to dividend income correctly. Single-account plans collapse to share = 1 and behave intuitively. Empty-pool guard prevents division-by-zero when no brokerage accounts are present.

3 new validation tests in test-validation.js lock the year-over-year behavior: untouched brokerage grows dividend income, drawn-down brokerage shrinks it, no brokerage accounts produces zero with no NaN. 7 new tests in test-ui-paths.js cover the migration stuck-state, both-populated-non-conflict, and idempotency cases.

v6.15.3
Validation completeness + QBI threshold consolidation

Three small post-SE-module cleanups:

Total tests in merged validation-results.json: 616 (up from 586 at v6.15.2). Engine math unchanged.

v6.15.2
Projection Table — Conversion Tax column

New Conv Tax column in the year-by-year Projection Table: federal income tax owed specifically on Roth conversions for that year (a subset of Federal Tax). Surfaced separately so you can see exactly what each conversion year costs in tax. Engine math is unchanged — conversion tax is computed as the delta between actual ordinary income tax with the conversion and the no-conversion baseline, and is paid from your designated tax source (cash, brokerage, or IRA withholding) outside the regular retirement-year tax cascade.

This closes a "where did my money go" gap reported by users running Roth conversions: conversion tax was paid from the designated source separately from the cascade, producing brokerage drain that didn't match the W/D column. The new column makes the conversion-year tax explicit. Auto-hides for users who don't run conversions (all-zero filter, same pattern as the existing TAD / TAD Tax columns).

The same field also added to the chart-overlay categories (so users can include Conversion Tax in the multi-line chart above the table) and to the CSV export. Engine field conversionTax has been in year output since v6.0; this surfaces it in the most-used view.

v6.15.1
Dashboard "This Year's Plan" cleanup

Two clarity fixes on the dashboard "This Year's Plan" card, both in response to user feedback:

Engine math is unchanged. The Working-tab cash flow definition is also unchanged.

v6.15
Solo 401(k) Contributions for Self-Employed Users

Self-employed users can now model Solo 401(k) contributions: employee elective deferral (Traditional or Roth) and employer profit-share. The engine handles all the cross-cutting tax interactions: §402(g) aggregation across W-2 and Solo deferrals; §415(c) annual addition cap on combined employee + employer; §404(a)(8) 20% sole-prop employer limit on (net SE − half-SE-tax); age-based catch-up including the SECURE 2.0 §109 enhanced catch-up for ages 60–63; AGI reduction for traditional contributions; QBI reduction for traditional employee, traditional employer, and Roth employer per Treasury Regulation §1.199A-3(b)(1)(vi) and IRS Notice 2024-2 Q&A L9.

The Self-Employed card on the Income tab already had Solo 401(k) input controls (added in v6.0 as scaffolding); v6.15 wires the engine math behind them. Help text now flags the QBI interaction with Roth employer contributions.

Engine simplification: the §402(g) capacity calculation uses your W-2 401(k) deferral target from Contribution Routing. If your annual savings pool is insufficient to fund the full W-2 target, the engine slightly understates available Solo deferral capacity by the savings-pool shortfall. Rare for typical SE users; on the roadmap for a future precision update.

Roadmap: SEP-IRA, SIMPLE-IRA, defined benefit plans, after-tax / Mega Backdoor Roth contributions, S-corp employer contribution math (25% of W-2 wages), and per-state §199A conformity are Phase 2 enhancements. SECURE 2.0 §603 mandatory Roth catch-up will ship with S-corp support since it requires FICA-wage tracking that sole prop / SMLLC / partnership entities lack.

26 new validation tests in test-self-employed.js (83 total, was 57). 503 + 30 main suites unchanged.

v6.14.1
SE module cleanup — cascade target, QBI baseline symmetry, validation page

Three small fixes to the self-employment module landing as a patch ahead of v6.15 Solo 401(k):

  1. The v6.8 tax-payment cascade target now includes SE tax for architectural correctness. Currently a no-op since SE tax only fires in working years and the cascade only runs in retirement, but the fix prevents a latent bug if a future feature allows post-retirement SE income.
  2. The per-baseline §199A QBI computation now applies the tax-loss-harvesting ordinary offset to all three projection scenarios uniformly (no-conversion, conversion-only, actual), eliminating a small asymmetry in conversion delta math for self-employed users actively running TLH near the SSTB threshold.
  3. The public validation page (/validation.html) now includes the 57 self-employment test results that previously ran in a separate file and weren’t surfaced.

New run-all-tests.js wrapper script runs all three test files (test-validation.js, test-spousal-ss.js, test-self-employed.js) and merges results into validation-results.json. Standalone test runners continue to work for development. build-validation.js now produces validation.html with 560 tests across 65 categories (was 503 / 58).

v6.14
Section 199A QBI Deduction

Self-employed users now receive the §199A Qualified Business Income deduction automatically. The engine computes 20% × (net SE earnings − half-SE-tax deduction) per business, applies the SSTB phaseout for users above the income threshold, caps the combined deduction at 20% × (taxable income − net capital gain) at the household level, and applies the new $400 minimum deduction added by the One Big Beautiful Bill Act for taxpayers with at least $1,000 of QBI.

2026 thresholds per IRS Rev. Proc. 2025-32 §4.26: $403,500 MFJ ($553,500 phase-in completion) and $201,750 single ($276,750 completion). The OBBBA extended the phase-in range from $100,000 to $150,000 MFJ and from $50,000 to $75,000 single.

The deduction is computed per scenario across all three projection baselines (no-conversion, conversion-only, conversion-plus-TAD) so Roth Conversion Optimizer recommendations correctly capture conversion-induced QBI loss when conversion pushes a user across the SSTB threshold. The Tax-Aware Drawdown smartFill bracket-room calculation also accounts for QBI, ensuring SE users get accurate target-bracket recommendations.

State-level §199A conformity is on the v6.x backlog (most states conform but California, New Jersey, and Pennsylvania do not). W-2 wage / UBIA modeling for SE businesses with employees, QBI loss carryforward, and aggregation elections are also Phase 2 enhancements. Solo 401(k) contributions further reducing QBI per Treas. Reg. §1.199A-3 will land alongside the Solo 401(k) contribution math in v6.15. 13 new validation tests in test-self-employed.js (56 total, was 41); 503 + 30 main suite tests unchanged.

v6.13
Self-Employment Tax

Net Self-Employment Earnings now flow through the engine. Positive earnings produce SE tax (IRC §1401: 12.4% OASDI on net × 0.9235 sharing the SS wage base with W-2 wages per §1402(b)(2), plus 2.9% Medicare with no cap). The half-of-SE-tax deduction (IRC §164(f)) reduces AGI. Negative net earnings — business losses — reduce AGI for the year with no SE tax owed.

SE tax is included in the total annual tax bill, and the v6.8 tax-payment cascade automatically draws it from the portfolio in retirement years. Three new fields surface in the projection year output: seTax, seNetEarnings, and seHalfDeduction. SE income propagates correctly through MAGI, IRMAA, ACA subsidies, SS taxation, and state tax (which uses the same federal AGI starting point most states piggyback on).

Solo 401(k) contributions and the QBI deduction (IRC §199A) are still on the roadmap (v6.14 and v6.15 respectively); the Self-Employed card on the Income tab indicates which features remain pending. 20 new validation tests in test-self-employed.js (41 total, was 21).

v6.12
Monte Carlo per-year percentile envelopes & Roth/TAD recommendation baseline

Monte Carlo per-year percentile envelopes. The p10/median/p90 lines on the Monte Carlo chart are now true per-year percentile envelopes across all simulations, not three sample paths chosen by terminal net worth. Previously, the median path could appear above the p90 path at intermediate ages because the path that ended highest may have started below the median path. With per-year envelopes, p10 ≤ median ≤ p90 is guaranteed at every age. Final-year values are unchanged.

Roth vs TAD legacy recommendation now considers all four strategies. The Longevity Crossover chart already plotted No Strategy alongside Roth Only, TAD Only, and Roth + TAD, but the recommendation text only compared Roth vs TAD — so it could claim “Roth wins at all ages” even when No Strategy was higher than both. Now the recommendation identifies the winning strategy across all four at the youngest and oldest age in the range, and reports any crossover. This catches cases where No Strategy beats Roth or TAD because the conversion/drawdown tax cost outweighs the heir-bracket discount on pre-tax inheritance.

6 new validation tests for the Monte Carlo envelopes (locking p10 ≤ median ≤ p90 at every age plus 5 supporting invariants). Total validation tests: 503. Spousal-SS suite unchanged at 30/30.

v6.11
Social Security display precision

FRA is now displayed in human-readable form (e.g., “66 yrs 4 mos” instead of “66.3”), eliminating the false-equivalence problem where a fractional FRA (66.333… for birth year 1956) and a user-entered claim age of 66.3 displayed identically. Sub-1% claim-age reductions now show with one decimal place (“reduced 0.3%”) instead of being rounded to the contradictory “reduced 0%.”

The loud red “Claiming before FRA permanently reduces benefit by X%” warning is suppressed when the reduction is below 1% — the inline label is sufficient for tiny reductions. SS Claim Age help text now shows the user’s actual FRA in human-readable form and clarifies that the input is interpreted as decimal years (66.5 = 66 yrs 6 mos, not 66 yrs 5 mos).

No engine or math changes — projections are identical to v6.10. All 497/497 validation and 30/30 spousal-SS tests remain green.

v6.10
Inherited Roth IRA Back-Load Option

Inherited Roth IRA accounts now support an optional back-load distribution timing: zero distributions during years 1–9 of the 10-year window, full balance in year 10. This pattern is fully legal under IRS T.D. 10001 (July 19, 2024) — inherited Roth IRAs have no annual RMD requirement during the 10-year window, only the year-10 deadline. At positive return rates, back-loading captures more tax-free growth than the default even-spread. Lifetime tax is unchanged (Roth distributions are tax-free regardless of timing).

Restricted to inherited Roth accounts; inherited traditional IRAs continue to use even-spread because the “at least as rapidly” rule may apply when the decedent died on or after their RBD — a future enhancement could add a decedent-RBD toggle to unlock back-load on traditional inherited accounts.

The new toggle appears below the regime dropdown when an inherited Roth account is on the post-2019 regime (it’s hidden for pre-2020 stretch and EDB regimes, which use Single Life Expectancy math). 7 new validation tests lock the behavior. Total validation tests: 497.

v6.9
Brokerage Dividend Yield

New optional field on brokerage accounts: Dividend Yield (% per year) and tax type (qualified or ordinary). Splits the existing return rate into a dividend portion (recognized as income annually) and an appreciation portion (unrealized until withdrawal). Qualified dividends taxed at LTCG preferential rates per IRC §1(h)(11); ordinary dividends taxed at marginal rates. Reinvested dividends step up cost basis dollar-for-dollar per IRS Pub 550. Total return rate is unchanged — this is purely a tax/accounting split. Useful when a brokerage account holds high-yield holdings whose dividend income materially affects MAGI, IRMAA, NIIT, or ACA eligibility.

Dividend income flows through the same tax pipeline that already handles qualified-dividend Income Streams: SS taxation (IRC §86), LTCG bracket stacking (IRC §1(h)(11)), NIIT (IRC §1411), MAGI, IRMAA, ACA, and state tax. Existing accounts with no dividend yield set are fully backward-compatible (the field defaults to 0 and no dividend income is generated).

10 new validation tests (6 direct feature tests, 4 regression tests locking the existing-correct qualified-dividend pipeline) lock the new behavior. Total validation tests: 490.

v6.8
Tax Payment from Portfolio

The engine now correctly draws from your portfolio to pay retirement-year federal income tax, state income tax, capital gains tax, and Net Investment Income Tax. Previously these taxes were computed and shown in the projection but did not actually drain account balances, leaving projections optimistic. Conversion tax (if you have Roth conversions enabled) continues to be paid from the source you've designated on the Roth Conversion tab — that part hasn't changed.

Mechanically, the engine wraps the gap-fill withdrawal cascade in a fixed-point iteration. Each pass computes the gap, draws from your accounts in your configured withdrawal order, computes the resulting tax bill, and feeds that tax bill back into the next pass's gap. The iteration converges in 2–4 passes per retirement year for typical scenarios. Years where iteration converges slowly (usually right at bracket transitions, IRMAA tier boundaries, or RMD-onset years) get a small ⓘ indicator next to the Fed Tax column in the Projection table — see the manual for details.

What you'll notice: The same plan inputs will produce projections noticeably more conservative than v6.7.5. Terminal net worth comes in lower, withdrawal totals reflect the actual tax outflow, Monte Carlo success rates are a few points lower for tax-heavy plans. Your plan didn't get worse; the model got more accurate.

The Roth Conversion Optimizer's recommendations may shift more than other surfaces. Pre-v6.8, the no-conversion baseline benefited disproportionately from the bug because its larger future RMD-era tax bill went unmodeled. Under v6.8, with that tax bill correctly drained from the portfolio, conversions look more attractive than they did before — sometimes meaningfully so. If the Optimizer previously recommended against conversions for your plan, re-run it under v6.8. The new math may give a different answer; for some plans, the direction of the recommendation reverses.

v6.8 also implements the IRC §408A(d)(3)(F) 5-year conversion clock. Each Roth conversion now carries its own 5-year window for purposes of the 10% early-withdrawal penalty on conversion principal. If you withdraw converted principal from your Roth before age 59½ AND within 5 years of the conversion year, the engine applies the 10% penalty. This matters most for users planning a Roth conversion ladder — converting Traditional IRA to Roth in your 50s and accessing the converted principal during the 5-year window. The 5-Year Rule Tracker on the Roth Conversion tab shows which conversions have matured. Users with substantial direct Roth contributions and aggressive early withdrawal plans may see slightly overstated penalties — full §408A(d)(4) ordering is on the v6.9 backlog (see manual for details).

Recommendation if you've saved a plan in v6.7.5 or earlier: open it under v6.8 and re-run your Strategy Report and Roth Optimizer to get fresh recommendations against the corrected baseline. The projections will recompute automatically on open; the strategy comparisons regenerate when you open those tabs.

11 validation tests in a "Tax Payment from Portfolio" category and 7 tests in a "Roth Conversion 5-Year Rule" category lock the new behavior. Total test count: 696 across all suites (validation 480, spousal-ss 30, self-employed 21, ui-paths 48, joint-life 117).

Verification. v6.8's engine math was audited across 8 categories against external authorities (IRS, SSA, CMS, HHS, statutory law, and mathematical theory). All 8 audit items pass. The verification trail is in the repo at audit/v6.8/phase1/ — readable per-item findings with cited authorities, test cases, and mathematical reasoning for the iteration math.

v6.7.5
Roth Optimizer ranks under blended returns + divergence warning

When users set per-account return rates that diverge across pre-tax and Roth (e.g., bond-heavy pre-tax at 5%, stock-heavy Roth at 9%), the Roth Optimizer’s candidate projections compounded the spread into a fictitious advantage for conversion that had nothing to do with taxes — converted dollars appeared to jump from a slow-growth bucket to a fast-growth bucket, and the “Maximize Net Worth” mode amplified the bias the most. Reported on Bogleheads.

The optimizer now ranks every candidate strategy using a blended return rate (the Nominal Investment Return from Assumptions) for all non-cash accounts. Cash accounts keep their actual rate because cash interest is taxed as ordinary income each year and changing its rate would distort MAGI/IRMAA scoring rather than just bucket growth. Important: only the optimizer’s candidate ranking is blended. Your main projection, Strategy Report, Monte Carlo, and applied optimizer results all continue to use your actual per-account returns — only the comparison inputs are normalized.

Independently, when pre-tax and Roth balance-weighted return rates differ by 2 percentage points or more (and both buckets hold $10,000 or more), the optimizer card now surfaces a warning explaining the bias risk for the main projection and how to remove it (set the same return rate on all accounts in the Accounts tab, or leave them blank to inherit the Nominal Investment Return). A second disclosure note above the strategies table explains that ranking uses blended returns and applied results use real returns.

Validation suite gained an Optimizer Blended Returns category covering the helper’s normalization, idempotency, immutability, the divergence threshold logic (boundary at exactly 2.0pp inclusive, balance gate at $10,000, missing-bucket handling, balance-weighted averaging across multiple accounts), and an end-to-end integration test confirming that blending materially changes projected end-state Roth balances.

v6.7.4
Cash/HYS account stranded-balance bug fix

The default plan and two of three demo families seeded their Cash / HYS account with a legacy schema (type:'cash') that the projection engine’s bucket filters did not recognize. The balance appeared in the Inputs > Accounts “Total Portfolio” and the Dashboard “Current Net Worth” (which both summed all accounts blindly), but was silently excluded from the projection. Reported on Bogleheads.

The fix has four layers: a pure canonicalizeAccount helper in the engine module that rewrites the legacy schema to the canonical type:'taxable', subtype:'cash' form; a migration step in migrateParams that runs the helper on every load (idempotent — safe for plans already in canonical form); seed-data fixes in the default plan and demo families; and bucket-aware totals in the Inputs and Dashboard tabs that filter to recognized account types and surface a visible warning if any unrecognized account is detected. Existing saved plans are migrated automatically on next load.

Defensive: the new total-hardening guards against future schema drift — if a new account type is introduced and an old build evaluates a plan saved under the new schema, the warning fires instead of silently undercounting.

Validation suite gained a new Account Schema Canonicalization category covering the helper’s normalization, idempotency, pass-through for canonical types, and an end-to-end integration test confirming a legacy cash account placed via the helper lands in the engine’s cash bucket.

v6.7.3
Break-Even Tax Rate display clarified

The Conversion Impact Analysis card’s Break-Even Tax Rate (BETR) display previously read “Convert if future rate > X%” with a tooltip describing it as the “future marginal tax rate”. That framing was misleading: BETR is not compared to your current marginal rate — it’s the average effective rate the no-conversion pretax pool would need at withdrawal for conversion to break even, measured against the projection’s implicit effective rate.

The distinction matters because for retirees with modest pretax balances, the projection’s effective rate on the pretax pool can be much lower than their marginal rate — standard deductions, senior additions, and the OBBB senior deduction shelter most of the pool from tax. A user reading “BETR 1.2%, my future marginal will be at least 12%, so convert” was getting the wrong answer in cases where the projection’s Final NW Δ was already showing the conversion losing money.

The card’s sub-label now reads Future effective rate threshold, and the tooltip explicitly disclaims the marginal-rate reading. The iOS manual’s BETR explanation got the same correction. The math is unchanged — only the labels and explanations are clearer. Final NW Δ remains the bottom-line answer when these metrics seem to disagree.

v6.7.2
Documentation pass: v6.4–v6.7 alignment

Documentation update bringing the user manual, feature list, and LLM crawler files current with changes shipped over the past several batches.

Manual. Added a Phased Brackets paragraph under Roth Conversion Strategies covering the v6.7 multi-phase feature. Added an escrow-exclusion clarification to the Liabilities tab Monthly Payment description (matching the v6.4 in-app help text). Replaced specific pre-v6.6 dollar amounts in the Relocation Scenario example with descriptive language — the actual savings now depend on your move age, remaining retirement years, and home equity, and the engine computes them precisely from your inputs.

Features. Added Phased Brackets to the Roth Conversion Strategies card. Updated the projection chart cap from “up to 4” to “up to 6” matching the v6.4 bump.

LLM crawler files. Updated test counts in llms.txt and llms-full.txt to 417 (matching the validation page). Added Phased Brackets to the strategy list in llms-full.txt so AI assistants give accurate answers about the feature.

No engine math changes. All 633 tests passing.

v6.7.1
Multi-phase hygiene + stale banner removal

Three small bug fixes from the v6.7 multi-phase Roth Conversion feature crossing module boundaries, plus removal of the long-stale “What's New in v5.0” dashboard banner.

Strategy Report alternatives now correctly test single-target. The dashboard's Strategy Report tests alternative strategies (e.g., “Smart Fill Roth 22%”) against your current plan. Previously, when you had Phased Brackets configured, those alternatives were inadvertently using your phased setup with overridden start/end ages — a mislabeled comparison. Fixed: alternatives now explicitly clear phases for an honest single-target comparison.

Roth Optimizer apply now clears phases. When you apply an optimizer result, your prior Phased Brackets setup is explicitly cleared (it was previously preserved invisibly, which could silently reactivate if you switched strategy back to Fill Bracket later).

Plan summary reflects phases. The Strategy Check-In card and AI Guide context now show “Roth Smart Fill (Phased)” or similar when phases are active, instead of falling back to the legacy single-target percentage.

“What's New in v5.0” banner removed. The dashboard banner introduced with v5.0 was hardcoded and hadn't been updated through nine subsequent version bumps. The full changelog page is the canonical source for what's new — the banner pattern was creating more confusion than it cleared up.

AI Guide reference updated. The BYOK AI feature reference now describes Phased Brackets so Claude/GPT/Gemini answers about the feature are accurate.

No engine math changes. All 633 tests passing.

v6.7
Multi-phase Roth Conversion brackets

The Roth Conversion tab's Fill Tax Bracket and Smart Fill (IRMAA-Aware) strategies now support phased bracket targets — define different target brackets for different age ranges within your conversion window. Useful when you plan to move to a different state mid-conversion (the canonical example: California 12% bracket while in CA, then 24% in Washington with no state tax, optionally back to 12% if you return to CA later).

Toggle “Use Phased Brackets” on the Roth Conversion tab when Fill Bracket or Smart Fill is your strategy. Add as many phases as you need, each with its own age range and target bracket. First-match-wins if phases overlap; years not covered by any phase produce no conversion. The outer Start Age / End Age remain the master gate for the conversion window — phases subdivide within it.

Existing plans are unchanged. The engine falls back to your single targetBracket setting when no phases are defined, so saved plans continue to behave identically. The Roth Conversion Optimizer continues to test single-target candidate strategies.

6 new tests in a new Roth Multi-Phase category lock down the regression case (empty phases identical to absent phases), single-phase equivalence, two-phase ordering, gap-year zero-conversion, phase boundary inclusivity, and outer-window gating. Total now 417 tests in test-validation.js, 633 across all suites.

v6.6
Relocation Scenario moveAge honored by engine

The Relocation Scenario now correctly applies the origin state tax rate before the move and the target state tax rate from the move year onward. Previously the scenario overwrote stateCode at the top of the projection, so the target state's rate was applied to every year — including pre-move years — producing inflated “tax savings” numbers when comparing against the baseline. The engine now resolves an effectiveStateCode per simulation year using the moveAge cutover, and both the pre-retirement and post-retirement state-tax call sites consume that resolved code. Behavioral change: pre-existing Relocation scenarios will show smaller state-tax-savings deltas than before — the new numbers are accurate, not a regression. Seven new tests added in a dedicated Relocation Scenario validation category covering no-relocation regression, pre-move year, post-move year, exact cutover boundary, move at currentAge, move beyond endAge, and pre-retirement move.

v6.5.1
Dangling label fix

The Projection tab's category selector instruction now reads “Select up to 6 categories” — the cap was raised to 6 in v6.5 but the user-facing label still said 4. Same fix applied to the corresponding sentence in the manual. Cosmetic only; no behavior change.

v6.5
UI polish — Effective Rate, more chart categories, larger legend text

Three small additions from user feedback. The Conversion Impact Analysis card on the Roth Conversion tab now shows an Effective Rate on Conversions stat alongside the existing Tax on Conversions — the blended average rate (total conversion tax ÷ total amount converted across all years). Compare it to the Marginal Rate Curve to see how much of the rate ladder a given strategy climbed.

The Projection tab chart can now overlay up to 6 categories simultaneously (previously 4). Useful for seeing how multiple income, expense, and balance series interact in the same view.

Chart legend text bumped from 10px to 12px across the app — Monte Carlo, Projection, Roth Conversion, Scenarios, and every other chart. More readable on small screens and at typical viewing distances.

v6.4
Mortgage amortization rebuilt — monthly accrual

Mortgage and loan amortization is now computed monthly: each month’s interest accrues on the declining balance from the prior month, matching how real fixed-rate loans amortize. Previously the engine used a single annual interest accrual (balance × annualRate once per year), which slightly overstated early-year interest and pushed payoff out by a few months on most loans. The same calculation now drives both the on-card payoff display in the Liabilities tab and the Debt Payments series in the Projection chart, via a shared amortizeYear() helper in src/engine/09-engine.js.

Existing plans with mortgages will recompute slightly different numbers — typically lower lifetime interest and an earlier payoff age. The shift is small (months, not years) but visible on next open. Plans without mortgages or loans are unaffected.

The Monthly Payment field on the Liabilities tab now has a help line clarifying that it expects principal & interest only — exclude property tax, insurance, and other escrow items. Many lender statements lump these together, and entering the full PITI value would inflate apparent payments and distort the payoff timeline.

11 new tests in a new Debt Amortization category lock the helper against textbook amortization values: year-1 interest/principal/balance for a 30-year fixed, 30-year payoff timing, zero-rate edge case, zero-balance edge case, underwater-payment edge case, and engine integration verifying the projection wires through the same helper. Total now 404 tests in test-validation.js, 620 across all suites.

v6.3
UI logic fixes — Earnings Test trigger and routing breakdown

Two refinements from user feedback. (1) The Social Security Earnings Test advisory in the SS tab now only appears when the user will actually have earned income overlapping the claim-to-FRA window — claim age strictly before retirement age. Previously the warning fired for anyone claiming pre-FRA, even when they would already be retired and have no wages, which was misleading. The engine itself was always correct; only the advisory text was over-eager. Same fix applied to the spouse advisory. (2) The Household Savings Summary in the Accounts tab now breaks the routed amount down by Traditional vs Roth, so the summary reflects the user’s actual Type selection on each contribution row instead of just showing a combined “401(k) + IRA” total.

v6.2
Label & string corrections

Five small fixes from user feedback. (1) The Accounts tab now reads contribution limits from the regulatory module instead of a stale hardcoded label, so the IRS Notice 2025-67 figures ($24,500 401(k), $7,500 IRA) match what the engine actually applies. (2) The “Break-even vs 62” column in the SS Claiming table now has a tooltip explaining what the age means. (3) “TAD” is now spelled out as “Tax-Aware Drawdown” on the Roth Conversion tab where the acronym first surfaces. (4) The QCD eligibility age now renders as 70½ rather than “701/2”. (5) The Projection tab chart category labeled “Liabilities” is renamed to “Debt Payments” — the value is annual debt service, not outstanding balance, and the old label was misleading.

v6.1.1
Relocation Scenario Fix

Relocation Scenario fix. Clicking “Compare Relocation” on the Scenarios tab threw a TypeError and the scenario did not render. The scenario dispatch guard in src/27-ui-scenarios.js excluded the bear and hcInflation string scenarios but not relocation. Replaced the deny-list with a positive typeof === 'number' check. Reported by an app user.

v6.1
OBBB SALT Cap Alignment & v6 Polish

The SALT deduction cap is no longer hardcoded at $10K. A new saltCapFor(year, magi) helper in src/engine/07-regulatory.js implements OBBB Act P.L. 119-21 amending IRC §164(b)(6): $40,000 base cap for 2025-2029 with 1% annual growth, MAGI phase-down reducing the cap by 30% of excess above $500,000 (threshold also grows 1%/yr), floor of $10,000, and reversion to $10,000 TCJA baseline in 2030. Applied at three engine call sites: main deduction flow, Tax-Aware Drawdown scenario, and Smart Fill Roth conversion bracket-room calculation. The Smart Fill site had been silently applying the old $10K cap — a latent bug that conservatively under-sized Roth conversions for users in high-tax states. Now fixed.

Two new Tax Strategy workflow cards building on v6.0’s per-owner RMD tracking. Coordinate Dual-Owner RMDs covers account ownership assignment, identifying the earlier RMD start year, and aligning Roth conversion windows to the earlier-start spouse. Apply the Joint Life RMD Election covers the four eligibility conditions (spouse enabled, age entered, gap strictly greater than 10 years, sole beneficiary), enabling the election, and stress-testing survivor scenarios. Existing Find and Fill Your Tax Valley and Optimize Your Roth Conversion Strategy workflows gained dual-owner awareness sentences pointing users to the Staged RMD timeline insight in the Strategy Report Card.

Feature-knowledge entries updated throughout v6.0 work: FICA bullet in Tax Engine, new RMDs section (per-owner tracking, Staged RMD timeline, Joint Life election, spousal rollover), W-2 Detail opt-in, Self-Employed Income Model foundation. Per-owner and Joint Life RMD router templates added for the Guide. Counts refreshed: 14 workflows (was 8), 18 templates (was 13), 423 validation tests. Version banner and Anthropic model string updated.

Federal Tax bracket citations updated from Rev. Proc. 2024-40 §2.01 (2025 tax year) to Rev. Proc. 2025-32 §4.01 (2026 tax year) in validation-metadata.json and the VALIDATION_DATA test entries. IRS source URL updated from rp-24-40.pdf to rp-25-32.pdf. Top-of-page source grid card year label now reads “(2026).” Projection footer model-notes corrected from “2025 tax brackets” to “2026 tax brackets (OBBB Act; IRS Rev. Proc. 2025-32).” Standard Deduction citations intentionally retained at Rev. Proc. 2024-40 pending verification of the corresponding section in the new procedure.

The “Itemizing?” and “Bunch Year?” columns now render as Yes/No instead of 1/0 in the HTML data table. Totals row shows an em-dash for boolean columns instead of “Total.” Both columns also added to the CSV export as numeric 1/0 for pandas/Excel analysis. The Yes/No rendering became especially useful after the SALT cap update, which makes the engine legitimately flip between itemized (2025-2029) and standard (2030+) for high-SALT users.

manual.html and features.html SALT-related prose updated to reflect OBBB cap mechanics. src/24-ui-inputs.js SALT field help text and the Itemized Deduction Comparison blurb updated. src/29c-ai-guide.js Itemized vs Standard Deduction feature knowledge updated.

6 new tests in a new SALT Cap (OBBB) category covering the 2025 base cap ($40,000), 2026 growth ($40,400), 2030 reversion, phase-down at MAGI $550,000 (cap $25,000), phase-down floor at MAGI $700,000 ($10,000), and threshold growth verification. Total now 423 automated tests, 44 categories.

v6.0
Per-Owner RMD Tracking & Self-Employed Income Foundation
v5.8.0
Joint Life RMDs for spouses more than 10 years younger

When a spouse is more than 10 years younger than the IRA owner and is the sole beneficiary of the owner’s pre-tax accounts, the IRS allows RMDs to be calculated using the Joint Life and Last Survivor Expectancy table (IRS Pub 590-B Table II) instead of the Uniform Lifetime table (Table III). The Joint Life divisors are larger, so the RMD is smaller — meaningfully so at wider age gaps. At a 24-year gap, the RMD drops roughly 31%. RetIQ previously used Uniform Lifetime in all cases, which overstated RMDs for couples with this age structure.

A checkbox labeled “Spouse is sole beneficiary of my pre-tax accounts” now appears in the RMD summary card on the Accounts tab, but only when the plan has a spouse enabled and the spouse is more than 10 years younger. The checkbox is unchecked by default — it has to be affirmatively set because the IRS rule requires that the spouse be the sole beneficiary of the IRA, which is a separate legal election from having a spouse in the plan. Most beneficiary designations name multiple beneficiaries (e.g., spouse as primary and children as contingent) and do not qualify.

The engine re-evaluates eligibility every projection year. If the spouse dies during the plan, RMDs automatically revert to Uniform Lifetime the following year. If the owner dies first and the spouse rolls the IRA into their own, Joint Life no longer applies (the now-sole owner has no qualifying beneficiary under the rule). Eligibility requires all four conditions simultaneously: both spouses alive, flag set, spouse’s age tracked, and age gap strictly greater than 10. Exactly a 10-year gap does not qualify — the IRS rule is “more than 10 years younger.”

The table covers owner ages 72 through 120 and spouse ages 20 through (owner − 11), a total of 3,234 divisor cells transcribed from IRS Pub 590-B (2025 revision, Jan 21 2026 print). Cells where the age gap is 10 or less are intentionally omitted — those cases fall through to Uniform Lifetime.

Plans saved before v5.8.0 load without the new flag set, so RMDs match the pre-change behavior until the user explicitly opts in via the checkbox. No migration needed.

Validation: 374 tests passing, +13 from v5.7.16. The 13 new tests live in a new category (“RMD Joint Life”) and cover the IRS published worked example (owner 75 / spouse 64 = 25.3 divisor), the 11-year gap boundary, the 24-year user-reported scenario, the 10-year gap non-qualification, the flag-off disable, missing-cell Uniform Lifetime fallback, and the eligibility helper’s edge cases (null spouse age, spouse older than owner, flag unset). A separate developer-test file test-joint-life.js runs 117 thorough backward-compatibility sweeps across the full Uniform Lifetime age range — run locally; not part of the public validation report.

Source: IRS Publication 590-B, Appendix B, Table II — Joint and Last Survivor Life Expectancy. Treasury Regulation §1.401(a)(9)-9(d). IRC §401(a)(9).

v5.7.13
Mobile header width cap
v5.7.12
Mobile/tablet header polish
v5.7.11
Mobile header layout
v5.7.10
Activate path for installed PWA
v5.7.9
Global dollar toggle
v5.7.8
Plan Health & Big Levers toggle-aware
v5.7.7
Dollar Toggle: Dashboard Stragglers
v5.7.6
Dollar Toggle: Inputs Panel (Comparison Blocks)
v5.7.5
Dollar Toggle: Inputs Panel (Simple Sections)
v5.7.4
Dollar Toggle: Survivor Center
v5.7.3
Dollar Toggle: PDF Export & Scenarios
v5.7.2
Dollar Toggle Persistence & Broader Deflation
v5.7.1
Gemini Free-Tier Callout on Guide Tab
v5.7
Employer Plan Roth Conversion Gate

Many employer plans (401(k), 403(b), 457(b)) don’t permit in-plan Roth rollovers while you’re still employed — conversions from those accounts have to wait until you separate from service. RetIQ now models this with a per-account conversion gate. Each pre-tax account has a new dropdown under its row on the Accounts tab: Always (default, correct for IRAs and plans that permit in-service IRR), After primary retires, After spouse retires (when a spouse is enabled), or After specific age.

Under the hood, the engine partitions your pre-tax balance into a convertible pool plus a list of gated tranches. Gated tranches grow at the same weighted pre-tax return as the rest of the pool and roll into the convertible pool automatically when their gate opens. Roth conversions and Tax-Aware Drawdown cap at the convertible portion; RMDs, QCDs, QLAC, and regular withdrawals reduce the full pool proportionally so gated balances shrink along with the rest. No migration needed — accounts with no gate set default to Always, preserving all existing plan behavior.

Gated balances surface in three places: the Roth Conversion Optimizer card shows a gated-balance summary, the Strategy Report Card shows a cyan callout explaining why conversion-based strategies may show reduced amounts, and the AI Guide answers “in-plan conversion” / “employer plan” questions with your specific gated total. The Tax Strategy workflow (“Optimize Your Roth Conversion Strategy”) includes a new tip pointing users to the Accounts tab before running the Optimizer.

Demo: the Lees example plan now marks the spouse’s 401(k) as gated until the spouse retires, showing how the Roth Optimizer respects the constraint.

Dev: added a localhost/127.0.0.1 hostname bypass for the license gate so local QA works without the dev.html bootstrap dance. Zero impact on production behavior — the bypass only activates when the hostname matches a local dev server.

Validation: 361 tests passing, +11 from v5.6.4. New tests in Category 17 (Roth Conversion Gate) cover: convertible-pool cap, pool exhaustion mid-window, gate unlock at retirement age, backward compatibility (accounts without the field), spouse-gated age conversion, spouse-disabled coercion to “always”, specific-age gate, pool-identity reconciliation, and RMD proportional reduction.

v5.6.4
AI Settings Polish — Easier First-Time Setup
v5.6.3
AI Guide Quality Pass
v5.6.2
Guide Chat Reset & Layout Polish
v5.6.1
AI Settings Modal Fixes
v5.6
Eligible Designated Beneficiary (EDB) Stretch Exceptions

The inherited account regime dropdown now includes three additional options covering SECURE Act Eligible Designated Beneficiary exceptions to the 10-year rule: Disabled beneficiary (IRC §72(m)(7)), Chronically ill beneficiary (IRC §7702B(c)(2)), and Not more than 10 years younger than decedent. All three use the same IRS Pub 590-B Table I Single Life Expectancy stretch math as v5.5’s pre-2020 grandfathered regime.

The engine’s stretch-regime filter is now a set membership check rather than an equality test, so adding future stretch variants doesn’t require engine changes. Existing pre-2020 stretch and post-2019 10-year accounts are unaffected.

Surviving spouse (uses spousal rollover into own IRA — add as Pre-Tax / Roth instead), minor children (stretch-to-10-year transition at age of majority), and successor beneficiary pass-through on a non-spouse beneficiary’s death. These edge cases warrant financial advisor guidance.

349 validation tests pass (was 348): 1 new test confirms EDB Disabled routes to the same Single Life Expectancy math as pre-2020 stretch.

v5.5
Pre-2020 Stretch IRA Regime

Inherited IRA and Inherited Roth accounts now support a per-account regime selector. Default is Post-2019 (SECURE Act 10-year), which is v5.4’s existing behavior. The new Pre-2020 stretch (grandfathered) option uses IRS Pub 590-B Table I (Single Life Expectancy) with the subtract-1 method for non-spouse beneficiaries who inherited before December 31, 2019 and are taking distributions over their own life expectancy.

When pre-2020 stretch is selected, two new input fields appear: Age at first RMD (your age in the calendar year of your first required distribution) and Years elapsed (full years between your first RMD and today). The engine computes the forced annual distribution as balance ÷ (initial divisor − years elapsed) and decrements the divisor by 1.0 each subsequent year.

Stretch distributions feed the same income counters as post-2019 distributions: traditional flows through ordinary income, SS taxation, MAGI, IRMAA, and NIIT correctly; Roth distributions are tax-free. Balances grow at the nominal return rate between distributions and contribute to net worth.

Backward compatible by default — accounts without a regime field continue to use v5.4’s pooled post-2019 math exactly as before. 348 validation tests pass (up from 331): 10 new unit tests on the Single Life Expectancy helper + 7 integration tests covering migration safety, mixed-regime portfolios, and per-account tracking.

Not yet modeled (planned for later): Eligible Designated Beneficiary exceptions (surviving spouse, minor children, disabled, chronically ill, and beneficiaries within 10 years of the decedent’s age), extra voluntary distributions above the forced minimum, and successor beneficiary pass-through on owner death.

v5.4
Inherited IRA Account Types

Two new account types: Inherited IRA and Inherited Roth IRA. Enter the year inherited to start the SECURE Act 10-year clock. The engine tracks inherited accounts as separate buckets with forced annual distributions spread evenly over the remaining window. Inherited traditional IRA distributions are taxed as ordinary income and flow through SS taxation, MAGI, IRMAA, and NIIT calculations. Inherited Roth distributions are tax-free. Both types are automatically excluded from Roth conversions, Tax-Aware Drawdown, and standard RMDs.

Inherited distribution cash offsets spending needs before voluntary withdrawals from other accounts. Excess distributions are reinvested into brokerage with full cost basis tracking. Inherited accounts are not part of the configurable withdrawal order — distributions are forced on the 10-year schedule.

Inherited balances and distributions appear in the projection chart (3 new selectable categories), data table (3 new columns), and dashboard net worth stacked area. The Plan Summary shows an INHERITED badge with total distributions. Legacy composition includes any remaining inherited balance at end-of-plan. One-time expenses can now be withdrawn from inherited accounts.

The Strategy Report Card shows a new insight when inherited accounts exist, explaining they are excluded from all Roth and Tax-Aware Drawdown alternatives with the distribution deadline and total. The Roth Conversion tab displays a pink callout noting inherited pre-tax is not eligible for conversion and showing the excluded balance. A new Dashboard lever card shows the inherited distribution timeline, estimated tax cost, and deadline.

Manual updated with full Inherited IRA Accounts subsection covering 10-year distribution, Roth exclusion, RMD exclusion, tax treatment, spending priority, and spousal rollover note. Features and landing pages updated. New “Plan Around an Inherited IRA” guided workflow. 13 new automated tests (331 total) cover separate bucket tracking, distribution math, depletion timing, net worth identity, tax impact, Roth conversion exclusion, RMD exclusion, inherited Roth behavior, and non-interference with existing account types.

v5.3
50-State Tax Sync, Relocation Analysis & Automated State Tax Updates

Complete sync of all 50 states + DC to Tax Foundation 2026 data. 35 states updated: flat-rate corrections (NC, CO, GA, IN, KY, MS, UT, ID), bracket restructures (OH, MT, NE, OK, SC, AR, KS, ND), new high-income tiers (MD, NM, DC), Massachusetts 4% millionaire surtax added, and 13 states with inflation-adjusted thresholds and filing-status-specific brackets. New York’s bottom 5 rates lowered for 2026. All rates verified against the Tax Foundation’s authoritative spreadsheet.

New Relocation Scenario card in the Scenarios tab. Model moving to a different state with an optional home sale (§121 exclusion applied automatically), mortgage payoff, expense adjustment, and full before/after comparison. The Strategy Report Card now surfaces “Relocate to Florida” automatically for users in income-tax states, showing estimated lifetime state tax savings.

State tax rates now update from Cloudflare KV alongside federal regulatory data. Future rate changes are pushed to all users without an app update.

16 new state tax validation tests covering all updated states. 318 total tests passing.

v5.2
Dashboard Redesign

The separate Plan Summary paragraph, key metrics row, highest-impact lever cards, and Maximum Spending calculator are consolidated into a single tabbed card with three views: Snapshot (key metrics grid with active strategy badges), Focus Areas (highest-impact levers with max spending calculator), and Details (income, savings, and lifetime totals). Every number now appears exactly once — no redundancy between prose and metrics.

Replaces two stacked collapsible accordion cards with a single card using a Working / Retirement tab toggle. New features: Account Transfers section for Roth conversions and Tax-Aware Drawdown (marked “does not affect totals”), standalone Healthcare line item, ⊕ info icons for contextual notes, dimmed zero-value rows (e.g., $0 state tax in Florida), and a Net Annual Cash Flow bar at the bottom showing surplus or drawdown rate.

The four dashboard charts — Net Worth, Income & Spending, Taxes & RMDs, and Cash Flows — now display one at a time in a tabbed container instead of a 2×2 grid. Each chart is full-width and taller for better readability on all screen sizes.

Now uses a two-dimensional tab layout. Goal tabs run horizontally (Max Net Worth, Min Taxes, Min Tax+IRMAA, Max SS Income, Tax-Free Legacy). Strategy category tabs run vertically (SS Timing, Roth, Drawdown, Combined, Retirement Age, Tax Optimization, Asset Allocation). A green dot indicates which category contains the best alternative. Cross-tab insights link to the best overall strategy when it lives in a different category. Maximum 3–4 cards visible at any time.

v5.1
Dashboard Inflation View & Debt Amortization

The Today’s $ / Future $ toggle now appears on the Dashboard, not just the Projection tab. When enabled, all stat values (Peak Net Worth, End Net Worth, IRMAA, Peak RMD), the Plan Summary prose, and all four dashboard charts display in inflation-adjusted present-value dollars. Lifetime sums like total tax, total IRMAA, and total Roth conversions are deflated per-year before summing — giving you a properly weighted present-value total rather than a rough approximation.

Debts can now track a remaining balance and interest rate. When a balance is entered, the engine computes the interest/principal split each year, tracks the declining balance, and automatically stops payments when the debt is paid off — no need to guess an end age. The Liabilities tab shows each debt as a card with payoff age, total interest paid, and a principal vs. interest breakdown. Debts without a balance continue working as fixed monthly payments for obligations like alimony. Two new Projection chart categories — Debt Interest and Debt Principal Paid — let you visualize the paydown schedule.

The Roth Conversion Optimizer now tests conversion windows up to 40 years (previously 25). Early retirees with long runways benefit from a wider search that can find strategies spanning decades. Sampling increased from 20 to 30 windows for better coverage.

New opt-in controls in the Accounts tab let you specify exactly where your pre-retirement savings go: 401(k) deferral (Traditional or Roth) and IRA contribution (Traditional or Roth), with the remainder flowing to brokerage. Previously, savings were auto-split 60/25/15 across Pre-Tax, Roth, and Brokerage. Routing amounts stay constant across income phases and savings growth. Employer match is always calculated against your 401(k) deferral and deposited to Traditional Pre-Tax, regardless of your 401(k) type. Available in Full mode only — Simple mode retains the automatic split.

v5.0
AI Guide — Bring Your Own Key

New Guide ✦ tab with an AI-powered assistant that knows your plan, your numbers, and every RetIQ feature. Ask questions like “Am I on track?”, “Should I explore Roth conversions?”, or “How do I prepare my spouse?” — and get answers personalized to your actual plan data.

13 pre-written answers cover the most common retirement planning questions with instant, accurate responses that cite your real numbers and walk you through the app step by step. No AI model needed for these — they work offline. Topics include Roth conversions, IRMAA, Social Security timing, stress testing, survivor planning, legacy, healthcare, spending, and Tax-Aware Drawdown.

For questions beyond the templates, connect your own API key from Anthropic (Claude), OpenAI (GPT), Google (Gemini), Perplexity, Meta (Llama), Groq, DeepSeek, or Mistral. Your key is stored locally in your browser. Plan data is sent to your chosen provider only when you ask a question — never stored, never logged by RetIQ. You pay the provider directly (typically a few cents per conversation).

The Guide’s welcome screen analyzes your plan and shows personalized suggestions based on detected patterns: high pre-tax balance with no Roth strategy, significant IRMAA surcharges, single-life pension with a spouse, plan running short, or early retirement without healthcare. Tap any suggestion for an instant detailed answer.

The 8 Guided Workflows (Tax Valley, Roth Optimization, ACA Coordination, Stress Testing, Survivor Risk, Spouse Roadmap, Pension Survivor, Legacy) continue to work exactly as before. The AI Guide is an additional way to get help, not a replacement.

API keys are stored in your browser’s localStorage on your device only. When you ask a question, your plan summary and the question are sent through RetIQ’s stateless Cloudflare Worker proxy to the selected provider. The proxy forwards the request and returns the answer — it never stores, logs, or inspects your key or data. Without cloud AI enabled, all computation stays 100% local.

Marginal Rate Curve — Tax Torpedo Visualization

New "Analyze Marginal Rates" chart on the Roth Conversions tab. Sweeps conversion amounts from $0 to your pre-tax balance and plots the true effective marginal tax rate at each level. Reveals the "tax torpedo" — where SS taxation stacking, capital gains bracket shifts, OBBB senior deduction phaseout, and IRMAA surcharges all compound on the same dollar. Your current conversion amount is shown as a reference line.

v4.8
Strategy Check-In

New Dashboard card that tracks whether your active strategy is still optimal as your portfolio changes. Click “Save Check-In” to snapshot your current metrics and strategy. When you later update account balances, the card compares your new projection against the snapshot and shows one of three states:

The card answers: “Given where my portfolio actually is today, should I change anything?” Update Snapshot to accept the new baseline, or click Review to jump to the Strategy Report Card.

v4.7.2
Roth Chart Fix, Guided Workflows & Strategy Report Clarity

Fixed the Conversion Advantage chart and breakeven age calculation, which were double-counting conversion taxes paid from cash or brokerage. Since v4.6 added explicit conversion tax deduction from accounts, the chart’s cumulative tax adjustment was subtracting those taxes twice — making conversions look permanently unprofitable. The chart now correctly excludes conversion taxes (already reflected in net worth) from its tax adjustment. Breakeven ages and the Conversion Advantage line are now accurate. Affects both the Impact Analysis and the Roth Optimizer charts.

Fixed Roth conversion alternatives in both the Dashboard and Survivor Strategy Report Cards. Alternatives were creating bare rothConversion objects that dropped the user’s IRA basis (Form 8606) and conversion tax source settings from v4.6. This overstated conversion tax cost for anyone with after-tax IRA contributions and mismodeled tax payment source. Alternatives now preserve all existing Roth settings while overriding only the strategy-specific parameters.

Four new workflows added, bringing the total from 8 to 12:

The Survivor Strategy Report Card now tests a “Deploy Cash to Brokerage” alternative, matching the Dashboard Strategy Report Card. Previously only available in the Dashboard.

Each strategy alternative now shows a category tag (SS Timing, Roth Strategy, Tax-Aware Drawdown, Combined, etc.) so users can see at a glance what Apply will change. New info box explains how Apply works: different-category strategies layer, same-category strategies replace, and Combined strategies change multiple settings at once. Each alternative uses its own preset parameters, not the user’s manual input tab settings.

New note at the top of the Roth Conversion Impact Analysis clarifies that it compares the user’s exact manual settings against no conversions, while the Dashboard Strategy Report Card tests different preset strategies. If results differ, the strategies are different — not contradictory.

New manual sections: “How Alternatives Are Tested” explains why Report Card results can differ from the Roth Conversions tab. “How Apply Works” documents the layering behavior with concrete examples and a recommended iterative workflow. Roth-related workflows updated with guidance on the Report Card vs. Impact Analysis relationship.

v4.7.1
QLAC — Qualified Longevity Annuity Contract

New engine feature for modeling a Qualified Longevity Annuity Contract purchased inside an IRA or 401(k). Enter purchase amount (SECURE 2.0 max $200,000), purchase age, payout start age (must begin by 85), and annual payout from your insurance company quote. The purchase moves money from pre-tax to an illiquid QLAC balance — not a taxable event. RMDs naturally decrease since the pre-tax balance is smaller. At payout age, guaranteed lifetime income starts, fully taxable as ordinary income. QLAC balance included in net worth. Strategy Report tests a $200K QLAC for plans with $300K+ in pre-tax accounts.

4 new QLAC tests. Total: 302 automated tests, 35 categories.

v4.7
Tax Optimization Suite

New engine feature that automatically detects unused room in the 0% long-term capital gains bracket each year and steps up brokerage cost basis at zero tax. IRMAA-aware — caps the harvest at the next Medicare surcharge threshold. Toggle in the Accounts tab (requires cost basis to be set). Visible in the Projection Table and tested as a Strategy Report alternative.

Enter your estimated annual harvestable losses and any carry-forward balance. The engine applies IRS rules each year: losses offset capital gains dollar-for-dollar, then up to $3,000/yr of ordinary income, with unlimited carry-forward. Projection Table shows the offset applied and running carry-forward. Strategy Report tests a $5K/yr TLH scenario.

When enabled, the engine compares standard and itemized deductions each year and picks the winner. Itemizable: SALT (capped $10K), medical expenses above 7.5% AGI, and non-QCD charitable giving (capped 60% AGI). Senior and OBBB additions apply only to standard. Inputs for SALT and medical in the Accounts tab; charitable giving flows in automatically from the Charity tab.

Concentrate 2 or 3 years of charitable giving into a single Donor-Advised Fund contribution. Bunch years itemize; off years take the standard deduction. Total giving unchanged. Toggle and cycle selector in the Charity tab. Strategy Report tests bunching with itemized deductions enabled.

Roth Smart Fill and Tax-Aware Drawdown Smart Fill now account for itemized deductions when computing bracket room. If your itemized total exceeds the standard deduction, the engine sees the larger deduction and converts or draws down more to fully utilize the bracket space.

Three new Dashboard lever cards proactively surface tax optimization opportunities: 0% CG Harvesting (when unrealized gains exist with 0% bracket room available), Tax-Loss Harvesting (for brokerage accounts over $100K), and Itemized Deduction comparison (when SALT + charity may beat the standard deduction). Each shows estimated lifetime savings and links to the relevant settings.

New in-app callout and manual section on the December conversion timing strategy: convert late in the year with IRS withholding to avoid estimated-tax penalties, then replenish via the 60-day indirect rollover. Covers the one-per-12-month rollover limit vs. unlimited direct trustee-to-trustee conversions.

16 new tests across 4 categories (CG Harvesting, TLH, Itemized Deductions, DAF Bunching). Total: 298 automated tests, 34 categories.

v4.6.1
Cash Drag Detection & UX Polish

New Dashboard lever card flags excess cash earning below market rate. Triggers when cash exceeds $100K and 15% of portfolio with a meaningful return gap. Shows the dollar amount above a 1-year reserve and the compounded opportunity cost over your projection horizon.

The Strategy Report Card now tests a “Deploy Cash to Brokerage” alternative that models moving excess HYSA funds into your brokerage while keeping a 1-year expense reserve. Ranked alongside other strategies under a new Asset Allocation category.

The 5-Year Rule Tracker card on the Roth Conversions tab is now hidden when all conversions happen after age 59½, since every row would show immediate access. The card still appears whenever any conversion is before 60.

The Tax Valley and Roth Strategy workflows now reference BETR, IRA basis, and conversion tax source in their step descriptions and checkpoints.

v4.6
BETR Framework & Roth Conversion Enhancements

The Conversion Impact Analysis now displays a Break-Even Tax Rate — the future marginal tax rate at which converting and not converting produce equal after-tax outcomes. If your expected future rate is above the BETR, conversion is favorable. Derived from Vanguard’s BETR research framework.

New input: Nondeductible IRA Basis. If your traditional IRA contains after-tax contributions, the engine now applies the IRS pro-rata rule — only the pre-tax portion of each conversion is taxed. Basis depletes proportionally as you convert over multiple years. Previously, all conversions were treated as fully taxable.

New dropdown: Pay Conversion Tax From. Choose between Cash/Brokerage (recommended — full amount stays in Roth), Cash Only, Withhold from IRA (less lands in Roth), or Not Modeled (legacy behavior). The engine now explicitly deducts conversion taxes from the selected account, with brokerage cost basis tracked proportionally on liquidation.

A new Insights card alerts high-income users whose traditional IRA balance blocks efficient backdoor Roth contributions due to the pro-rata rule. Explains how converting the IRA clears the obstacle and shows the annual backdoor contribution potential.

v4.5
Pre-Retirement Income Phases

Added income phase support to the projection engine. Each phase defines an age range with its own salary, savings amount, and growth rates. When no phases are defined, income works exactly as before — a single salary with uniform growth. When phases are defined, ages not covered by any phase fall back to base income rather than zeroing out.

New “Pre-Retirement Income Phases” card in the Income tab. Click “Add Income Phase” to create your first phase, pre-populated from your current income, savings, and growth rate. Add a second phase for a career wind-down, part-time period, or sabbatical. Each phase shows income at start and end ages. Spouse phases are supported independently.

Designed for people a few years from retirement who plan to take a lower salary, go part-time, or change careers before fully retiring. Previously, the only option was a single income with uniform growth — no way to model a pay cut at age 62 followed by retirement at 65.

v4.4
Projection Visibility, Spouse Fix & QA Improvements

Added six new columns to both the projection chart and data table: Other Income, Qualified Dividends, Tax-Aware Drawdown, TAD Tax Cost, HSA Balance, and HSA Contributions. These were already computed by the engine but not visible to users. All auto-hide when values are zero.

Previously selected chart categories that no longer had data (e.g., after disabling a feature) could become invisible but still count toward the 4-category limit, blocking new selections. Stale keys are now filtered automatically on every render.

Disabling and re-enabling the spouse checkbox now correctly preserves the spouse’s age. Previously, re-enabling left the age at zero, silently zeroing out spouse income, savings, and Social Security in the projection.

Fixed the “Reset to recommended order” button in the Assumptions tab, which was broken due to an HTML escaping issue. The button now works correctly.

Retirement age scenarios (Retire at 40, 50, etc.) are now hidden when below or equal to your current age, since they would produce identical projections to the baseline.

v4.4.1
Roth Optimizer: Wider Windows for Early Retirees

The optimizer now tests conversion windows up to 25 years (previously capped at 15). Early retirees with long runways to RMDs can now see Fill 12% strategies tested over realistic time horizons, giving the optimizer a fairer comparison between aggressive short-window conversions and conservative long-window strategies.

v4.3
Conversion & TAD Tax Payment

Roth conversion and Tax-Aware Drawdown taxes are now explicitly paid from non-retirement accounts (cash/HYS first, then brokerage) before year-end growth. Previously, the tax was computed and reported but not deducted from any account balance, slightly overstating net worth in conversion years.

The This Year card no longer double-counts conversion and drawdown taxes. Federal tax now excludes amounts already shown in the Roth Conversions and Tax-Aware Drawdown sections.

v4.2
2026 Tax Year Update & Automated Regulatory Monitor

All embedded tax constants updated to 2026 figures. Sources: IRS Rev. Proc. 2025-32, IRS Notice 2025-67, CMS Nov 2025, HHS 2026 FPL, IRS Rev. Proc. 2025-19.

Deployed a Cloudflare Worker that runs weekly. It fetches IRS, SSA, CMS, and HHS source pages, uses AI to extract updated figures, validates them against a strict schema, and pushes changes to Cloudflare KV. All three platforms receive updated tax data on next load with no app update required.

New Workflows tab (Full mode, Pro only) with 8 step-by-step walkthroughs for complex multi-tab analyses: tax valley optimization, Roth conversion strategy, ACA/Roth/withdrawal coordination, end-to-end stress testing, survivor risk analysis, spouse roadmap preparation, pension survivor benefit selection, and after-tax legacy optimization. Each workflow includes numbered steps, navigation cues, and checkpoint prompts.

After clicking Apply on any alternative strategy, a “Reset to Original” button appears. One click reverts all Apply experiments and restores your plan to where you started. The snapshot clears on page reload.

Scenario buttons replaced with a grouped dropdown menu (Retirement Age, Social Security, Expenses & Returns). Added Retire at 40 and Retire at 50 scenarios. Cleaner on mobile — renders as the native iOS/Android picker.

Return rates are now clamped to −5% – 25%, growth rates to 0% – 20%, inflation to 0% – 15%, and SS COLA to 0% – 10%. Prevents accidental entries (e.g., typing 76 instead of 7.6) from producing runaway projections.

Raised the simultaneous chart category limit from 3 to 4 in the Projection and Scenarios tabs.

v4.1
Tax-Aware Drawdown, Dawn Theme & More

Voluntary pre-tax withdrawal strategy that fills a target bracket before RMDs begin, reducing future RMD burden. IRMAA-aware, OBBB-aware, integrates with the Roth optimizer. Proceeds land in brokerage with full cost basis for stepped-up basis at death.

Third theme alongside dark and light — warm cream palette with a purple accent. Now the default on all platforms.

Fifth Strategy Report goal. Ranks strategies by after-tax heir value: Roth + taxable (stepped-up basis) + HSA, minus pre-tax discounted by the heir’s bracket under the SECURE Act 10-year rule. Shown when legacy planning is enabled.

Dedicated tab (visible when a spouse is configured) with three sub-tabs: Overview, Strategies, and Adopt Plan. Supports adopting the survivor’s roadmap in both directions.

v4.0
Modular Architecture, Regulatory Data System & Freemium Model

Rewrote the build system. The app is now assembled from 36 modular source files plus a pure-math engine with zero DOM dependencies, enabling per-platform builds for web, iOS, and macOS from a single codebase.

Centralized all tax, Medicare, Social Security, ACA, and contribution limit constants into a single REGS data structure that fetches updates from Cloudflare KV on load. No app update required to receive new tax year figures. Falls back to embedded defaults if offline.

Launched a free Simple tier and $49.99 one-time in-app purchase for full unlock on iOS and macOS. Web remains $49 one-time via Stripe. The free tier includes data entry, basic projections, the dashboard, save/load, and the Johnson family example.

RetIQ is now available on the iOS App Store and Mac App Store, alongside the existing web app. All three share the same calculation engine and save file format.

Added the One Big Beautiful Bill Act senior standard deduction ($6,000/person, phasing out at 6% above $75K single / $150K MFJ, effective 2025–2028). Updated all affected brackets and validation tests.

v3.2
Life Insurance Modeling

Term and permanent life insurance policies modeled with annual premiums and tax-free death benefits (IRC §101). Supports multiple policies per person and spousal policies. Death benefits deposit into the survivor’s brokerage account at the time of death and are reflected in legacy composition.

v3.1
One-Time Cash Events & LTC Insurance Inflation

Model planned property sales, inheritances, or other lump-sum events at a specific age. Capital gains calculated automatically with IRC §121 primary home exclusion ($250K single / $500K MFJ). Proceeds can flow into the brokerage or cash account.

Long-term care insurance benefits now compound over time. Choose from None, 2%, 3%, or 5% compound inflation protection. The engine compounds the insurance benefit alongside projected care costs so projections reflect realistic coverage value at the age it’s actually needed.

v3.0
Essentials & Full Control Modes

Two modes, one engine. Essentials presents a streamlined view for straightforward retirement planning — fewer tabs, fewer fields, the same math underneath. Full Control reveals all tabs and every advanced feature. Toggle anytime without affecting your data or calculations.

v2.1
Monte Carlo Model Selection & Roth Optimizer Improvements

Added model selection: Historical (U.S. market distributions 1926–present), Normal (parametric), and Conservative (lower expected return). Each affects the return and volatility assumptions across 2,000 simulated paths.

Added IRMAA-aware Smart Fill — fills the target bracket while capping conversions before crossing an IRMAA threshold. Added custom schedule mode with a per-year editable table and a “Generate Optimal” button that finds the best conversion amount for each year in the window.

v2.0
Pension, Legacy Goals, Liabilities, LTC & Charitable Giving

Expanded pension modeling: survivor benefit options (single-life, joint & 50/75/100%), configurable taxable percentage, COLA, and start age. Survivor benefit flows into the surviving spouse’s income correctly.

Legacy composition showing after-tax heir value breakdown across account types. Target legacy amount with a gap indicator. Charitable bequest modeling.

Debt schedules for mortgages, alimony, student loans, and other long-term obligations. Each has an annual amount and end age, subtracted from cash flow in the years it applies.

Dedicated LTC tab with annual care cost, start age, duration, and LTC insurance benefit offset. 2025 national cost benchmarks embedded as defaults.

Annual giving with start/end age, one-time gifts, and Qualified Charitable Distribution from pre-tax accounts. QCD reduces MAGI dollar-for-dollar up to the annual limit, offsetting RMD income.

v1.9
ACA Subsidy Engine

Full Affordable Care Act premium tax credit calculation based on projected MAGI and household size. Supports both the enhanced subsidy table (ARPA/IRA, no income cliff through 2025) and the original table (400% FPL cliff) for post-2025 planning. Subsidy reduces out-of-pocket healthcare cost in the projection year by year.

v1.8
Healthcare Source Selection & Pre-Medicare Gap

Six pre-Medicare healthcare source options: ACA Marketplace, COBRA, Spouse’s employer plan, VA/Medicaid, Retiree plan, and self-pay. Each has a different default cost and medical inflation rate. The engine models the full gap between early retirement and Medicare eligibility at 65.

v1.7
Social Security Earnings Test

The SSA retirement earnings test for early claimers. Benefits withheld at $1 for every $2 earned above the annual exempt amount (under FRA all year), or $1 for every $3 (in the year of FRA). Withheld benefits are recredited as a permanent benefit increase after FRA. Exempt amounts indexed annually by the Average Wage Index.

v1.6
This Year Summary Card

Dashboard card showing the current year’s projected cash flows: income sources, withdrawals, conversions, taxes owed, and net. When retirement is within 5 years, a second card previews the retirement year’s prorated income and new tax picture.

v1.5
4-Account System, SSDI & Validation Suite

Separated Cash/HYS and Brokerage into independent accounts with configurable return rates, tax treatment, and withdrawal order. Cash interest treated as ordinary income; brokerage withdrawals trigger capital gains using a 50% cost basis estimate with 0/15/20% tiered rates based on income.

Social Security Disability Income modeled for both spouses, with conversion to retirement benefits at FRA and correct survivor rules.

Automated validation suite covering federal tax, SS PIA, IRMAA, ACA subsidies, RMDs, and more — each test citing its authoritative source (IRS, SSA, CMS). Viewable at retirementiq.app/validation.html.

Contextual help icons throughout input forms with plain-English explanations of retirement finance terminology.