Help · What's new

What's new

From RangefinderInvest's built-in help · newest release line first · the site ships version 0.49.3

0.49: Planning for the people who are actually there

A plan is about particular people, and this release is about the app knowing who they are. Guided setup now asks for the facts the projection cannot work without: every person's birth year and month, and a price source that can actually fetch. It no longer lets you walk past them into wrong numbers. Projection refuses to run on a household it cannot age. Health coverage before 65 is modeled per person instead of per household, which moves real money for couples in both directions. And the guided wizard and your Profile stop giving two different answers about the same three facts.

Your portfolio file is unchanged. Nothing is upgraded and nothing is asked of you when this version opens it.

0.49.3: Help got a careful edit

Every built-in Help topic has had a sentence-by-sentence line edit. Titles, headings, lists, notes, and release history now use more natural punctuation throughout. The meaning has not changed: calculations, technical claims, links, search terms, and task instructions remain intact. A source check now keeps future Help updates aligned with the same rule.

Nothing about your portfolio or the way the app works changed in this patch.

0.49.2: backups know which database they belong to

The Files page's Backups list mixed every database's snapshots together with no label. Retention has always been per database. Exploring a sample portfolio never rotates out your real portfolio's backups. The list didn't say so, and a keep-count next to a longer, unlabeled list looked broken. The active database's backups now lead the list; other databases' snapshots sit behind a collapsed section, grouped and still restorable or deletable individually. The Files page's other multi-part sections (the database path, the sample-portfolio grid, Start Fresh) also got a layout fix. They had been sharing a row with their buttons instead of stacking.

0.49.1: the demo households finished their profiles

The sample portfolios that ship with the app were advertising an unfinished profile. This release counts a spouse's birth month as a Profile refinement, and none of the built-in demo households had one, so every demo couple opened with its completeness ring stuck short of full, on exactly the screens meant to show the app in good order. The generated households now state a spouse's birth month outright.

Nothing in the app behaves differently, and a household you created yourself was never affected. This changed only the demo data bundled with the app.

Setup asks for what the plan needs

Every person needs a birth year and a birth month. A spouse without a birth year used to sail straight through setup, and the cost was invisible: their tax-deferred balance landed in a group the app read as roughly 2,000 years old, so required distributions forced nearly the whole balance out as taxable income in the first projected year, and survivorship silently switched itself off. Both setup routes now require every person present.

The Price data step resolves to a configuration that can actually fetch. Choose Yahoo, or enter a Tiingo key inline. Continue stays disabled until the resolved choice is proved. A Tiingo key is tested against the live service before you can move on, because a saved key can be revoked and being non-blank is not evidence that it works. Skip for now writes nothing at all, and says so. Before this, finishing setup on an unusable price source produced no error anywhere: your funds simply never got prices.

Leaving early leaves a reminder. The Finish setting up checklist opens with a Tell us about you row, and it now survives an exit with no accounts on file, including from the Stress-test my retirement route, which never recorded one. An established portfolio is still never nagged.

Projection blocks with a setup gate instead of reporting a number it cannot stand behind. When a birth year is missing the page names whose and offers to fix it. The calculation behind it, including the one the AI assistant uses, stops with a message naming the account rather than answering with wrong figures.

The example preview is one household

"Preview with an example" now substitutes a whole household, not a coat of paint. It only ever replaced the age, the balances and the spending. Every other fact a Profile supplies still came from your real household and was placed on a 35-year-old's clock: Social Security amount and claim age, filing status, state rate, taxable gain, housing, pre-65 health, pensions, survivorship. So the same button reported 66.9% success to the empty-profile tester it was built for and 100.0% to a 58-year-old already collecting. That was a success rate assembled from two households, which describes neither.

The example is now one person defined in one place: a 35-year-old single filer with $150,000 saved across three account types, putting away $18,000 a year to 65 and spending $48,000 a year after. The plan is calibrated so its own withdrawal rate reads comfortably inside the green band, because a sample plan its own gauge flags teaches the wrong thing on arrival. Its Social Security benefit is worked out from the published bend points rather than written down as a number that could quietly go stale.

Knobs you type on the Projection page itself, including windfalls, one-time withdrawals, the benefit-cut stress, and return and allocation assumptions, stay live and land on the example's clock. Anything the example cannot express is switched off rather than run on borrowed numbers, and every readout on the page states what the run actually used.

Health coverage, per person

The pre-65 premium and subsidy divide between you. The household's stated figures now split into equal per-person shares, each ending on that person's own 65th birthday and prorated by their own birth month. Before this, the whole pre-65 health cost was gated on the primary's age, which was wrong in both directions: the younger spouse's premium vanished at the older one's 65; with the older spouse listed second, the household paid a full couple premium past that person's 65 while also being charged their Medicare premium. The sharpest way to see it: in an otherwise identical plan, the same couple cost $120,000 or $168,000 depending only on which of them the Profile called "primary."

The subsidy cliff is still tested on the whole household's income, because that is how the ACA actually works, and the survivor carries their own share on their own clock. The even split is a simplification worth stating: a real family premium is the age-rated sum of its members', and the figure being divided is one blended number you typed.

A single filer's last marketplace year is billed on one clock. The premium used to stop dead on the 65th birthday while the lost-subsidy risk was prorated across the year. Anyone born February to December was therefore modeled as paying none of their final year's premium while still risking part of that year's subsidy. Both now share one enrolled fraction.

When a spouse starts Medicare is read from your Profile, not from a planning knob. Enrolment keyed off the scenario's spouse-age slider, a savings what-if, while the 65-and-over deduction and the marketplace transition read the Profile. The same person could leave the marketplace on one clock and start Medicare on another. Identity reads identity now; a spouse modeled as 50 for a contribution what-if still contributes on that clock. A saved scenario whose spouse-age knob was edited away from your Profile will see its spouse-Medicare timing move. That is the correction. Scenarios you never edited are unaffected.

Filing jointly with nobody on file no longer prices a person who may not exist. It used to invent a second Part B, Part D and IRMAA premium from a guessed "your age minus two." There is nothing to enrol now, and the app asks you to add the person in your Profile.

The wizard and the Profile agree

One fieldset, one verdict. Guided setup's About you step and Profile → Household ask for the same three facts about the same people, and until now they had two of everything, including two different answers about the same input. The wizard refused to continue on a birth year it could not store; the Profile accepted the save, wrote nothing, closed the panel, and left the projection gated with nothing on screen to say why the year you had just typed was gone. They are one fieldset and one rule now, which reports a field filled in wrong and stays quiet about a field left blank. What they still ask for differs on purpose: the wizard wants a birth month while you are already answering birth questions, and the Profile treats it as suggested.

Re-entering the About step no longer overwrites your filing status. The step guessed at it from whether a spouse was present and saved that guess every time. The retirement route sends an incomplete profile back through it. It reads your stored household now. The one case it still overrides is married filing jointly with nobody on file to be joint with, which is a default nobody has answered rather than an answer.

Finishing an account inside guided setup shows one success screen. "Account created" was followed one click later by "Account set up" saying the same thing under its own green banner. That screen is the question it always was: Add another account? It has its two choices in the footer like every other step, and the two differently-worded buttons that both ended setup are now one.

A % no longer sits alone on the line below its input, in six places across the Profile, under Taxes, Income, and Housing & health.

0.48: The numbers, checked against their sources

0.48.1: a smaller download. Every build on the release machine had been leaving its compiled main-process bundle behind under a new name, and the macOS installer packed all of them. Around 110 MB of the disk image was code no version of the app can load. The build clears that directory now, so 0.48.1 is about a third smaller. Nothing else differs from 0.48.0: same application, same data, same behaviour. Windows and Linux installers were never affected.

This release is about numbers being right rather than about anything new to look at. Every published tax and Medicare figure the planner works from was refreshed to 2026 and read off its primary source. A run of defects on the money path, including a sale taxed by the wrong rules, a stock split your holdings never picked up, a portfolio the backtest sold to cash, a mortgage payoff counted in the wrong dollars, were found and fixed. Two import defects that silently doubled things were reproduced against real broker exports and closed.

Opening this version upgrades your portfolio file if it was last opened on the 0.47 line. It is immediate, measured at 12 milliseconds on a 1.1 GB file holding 11.6 million price rows, and it happens once, the first time this version opens the file. Nothing is asked of you.

The 2026 figures

Every year-pinned number is now 2026, and each one names the document it came from. Federal brackets and the standard deduction ($16,100 single / $32,200 married filing jointly), the 65-and-over bonus deduction, the IRMAA income floors, Medicare Part B at $202.90, the 401(k) limit at $24,500 with an $8,000 age-50 catch-up, HSA limits at $4,400 and $8,750, the Social Security wage base at $184,500 and the benefit bend points. Two of them were wrong rather than merely a year old: the Part D premium was an unsourceable $46.50 that matches no published figure, and the topmost IRMAA tier used "greater than" where the rule says "greater than or equal to", so an income landing exactly on the threshold was placed a tier too low. Expect your projection to move: across the bundled samples, median lifetime tax falls and median spending rises, while the modeled success rate slips a few tenths of a point for households closest to Medicare. That last change reflects Part B at $202.90 against the old $185.00.

Contribution limits are now evaluated at each age the plan reaches, not once at your age today. Someone aged 61 kept the ages 60–63 catch-up at 64 and beyond; someone aged 53 never gained the age-55 HSA catch-up.

The money path

A sale inside a tax-sheltered account was taxed as though it were in a brokerage account. Rebalancing and the withdrawal orders estimated capital-gains tax from the lots of any account whose type they did not recognise as sheltered, and flagged wash sales and harvesting opportunities inside IRAs, Roths and HSAs where neither idea exists. The account's wrapper decides now. Where the tax genuinely cannot be known, as with a position whose lots are only partly imported, the estimate is blank rather than quoting the tax on the covered fraction as a firm number. And an HSA is the last account a withdrawal draws from, not the first: it used to sort ahead of taxable and tax-deferred money.

A stock split after your last statement showed a fraction of the position you hold. For an account tracked by statement rather than by transactions, stated share counts were priced without applying any split since. A 10:1 split after the last snapshot showed a tenth of the position in Holdings, in your allocation, in Rebalancing's drift and in the projection's starting balance, while the value chart beside them showed it correctly, because it used the other of two code paths. There is one path now.

Rebalancing ordered the difference twice for a fund named twice in one slice. Each line produced its own order, and each order covered the account's whole holding of that fund: $60,000 of a fund a slice listed twice came back as two "Reduce $42,000" orders: $84,000 of sales against $60,000 of stock. That total doubled again in the summary and the tax estimate. One fund is one row, one order and one stored line now, and models already carrying a doubled fund are repaired when the file upgrades.

A statement account's return was overstated whenever money went in. The time-weighted return assumed a deposit earned nothing for the whole period it landed in, while the value it grew into was still counted at the end. A book that doubled through a +10% market therefore read as +20%. A statement gives a period total and no dates, so a period's flow is now weighted at its midpoint. Separately, an account whose value reached zero with no matching withdrawal was skipped as if nothing had happened; that is a real −100%, and it is reported.

An early mortgage payoff was too large, by a growing amount. The recurring principal and interest were converted into today's dollars and the payoff balance was not, so one loan was carried in two different bases. The payoff was overstated by inflation compounded across the years between writing the note and clearing it, about 34% at 3% over ten years. The payoff-year explorer and the one-time expenses panel showed that same overstated figure under captions reading "today's dollars"; both now show what the projection actually draws.

A rebalance date the backtest could not price sold the whole portfolio to cash. If no fund in the model had a quote that day, every position was cleared and could not be refilled. A gap in our price data became a liquidation, and a single-fund comparison could score at −100%. The rebalance is skipped now, and the previous allocation rides through.

Two imports that doubled things

Re-downloading a broker export imported the same trades a second time. A broker that leaves the settlement date blank makes this app derive the trade date from the cash movement that funded it, then fills that column in months later, when settlement posts. The two exports describe one purchase with two different dates, and nothing matched them: on a real pair of Fidelity exports covering the same period, eleven Treasury-bill purchases imported twice, doubling both the shares and the cost basis. A derived date is recorded as derived now, and a row carrying one matches a firm date a few days away, while trades genuinely made days apart still import as two trades. Rows imported by earlier versions carry no such mark and are not guessed at; re-importing the export that created them teaches the app which ones they were.

Undoing an import could delete rows a later import also reported and take a holding off the page entirely. Only the run that first created a row was recorded, so undoing an earlier overlapping export removed rows a later, still-applied export also covered; and because a holding disappears once its shares net to zero, deleting an opening purchase while a later sale survived did not shrink the position, it removed the fund from Holdings. An import now records what it re-reported as well as what it created, and undo removes only what nothing else stands behind. Import history says when a run shares rows with another, and Undo names what it will actually delete. Imports made before this version carry no such record; their undo behaves as it did, and the app tells you so rather than guessing.

An import also lists every line the file did not turn into a transaction, by reason and line number. Two of those drops used to be completely silent, and one mattered: a Fidelity export re-saved from a spreadsheet quotes its header, which the parser did not recognise, so the file imported as zero rows and reported no problem at all. A recognised broker file with no usable header is refused in words now.

Research and prices

Model Backtest says when a holding it priced is not really priced, and Optimize shows when each candidate was last priced. A fund whose record simply stops used to be carried at its last close forever. Units you already hold are still valued there, but fifteen days after the last real close the fund stops attracting new money at a rebalance, and it is named. A fund whose quotes ran out is no longer shortlisted at all. A dead fund used to look like a winner under "Limit downside", because a flat stretch of stale price contains no drawdown and no volatility.

A Screener calendar year the fund's record does not reach is blank instead of wrong. A fund whose prices stopped in June still reported a full-year return for that year, using its January-to-June move against an index's whole year, and a flat 0.00% for every year after. Four more figures behind the scores were computed from data that was not there: the optimizer's consistency measure compared a half year against a full one, the "history" factor read the length of the risk window rather than the length of the fund's record, the concentration measure penalised patterns that are ordinary for the number of years being measured, and a candidate could be scored on fewer measures than the fund it was challenging.

The Screener's scoring settings now belong to the portfolio, not to the computer. About twenty-five knobs lived in this machine's browser storage, which meant a backup did not carry them, a restore on a new laptop scored with factory defaults, and a bundled sample was scored with your personal weights. Anything you had tuned is carried across the first time your own portfolio opens.

A split or a price you entered by hand can no longer be taken back by a download. A manual split used to replace whatever row held that date, irrecoverably destroying a provider's or a detected split. A blocked date is now reported by name instead of the dialog closing over a list that did not fully save. A price you typed with a statement survives a price-history rebuild from this version forward. The mark that protects it is new, so a price typed by an earlier version does not carry one and a rebuild can still replace it. Rebuilding one ticker from Tiingo is a single atomic replacement, so an interrupted rebuild cannot leave a fund with no prices at all. Cleaning up unused tickers keeps the price history of positions you closed, which the value and return charts still read.

Everywhere else

The last thing you clicked is the thing the app keeps. A settings toggle switched off before its switch-on finished saving compared itself against a value that had not moved yet, decided there was nothing to do, and left the earlier state in the database. Settings writes are queued per setting now, and a refused write rolls the screen back instead of leaving it ahead of what was stored.

Settings fields say when an entry cannot be used, instead of quietly doing nothing. Clearing Equity drawdown band, Reserve floor or Assumed inflation used to save a real zero, which left the Rebalancing banner permanently claiming equities were down. Project to age is bounded to an age above yours and no higher than 120: a mistyped horizon used to be saved and then freeze the Planning page on every visit. And a saved plan whose stored settings are damaged now opens on defaults rather than dropping the page to its error screen.

A dialog left open on one page no longer hangs over the page you moved to, the Holdings ledger no longer goes stale after an import or undo done elsewhere, and removing a spending phase, one-time withdrawal or conversion phase no longer moves your cursor into the row below it.

A matured bill or CD is its own state on Fixed Income, labelled with a Reconcile action instead of "Hold to maturity." The same is true for one whose maturity date cannot be read, which used to come back as "matures today" and count toward your near-term reserve. A ladder's income card leads with what the ladder settles into rather than with its ramp-up year.

The Dashboard built the same reading of your portfolio three times and now builds it once, which on a large book is seconds off every visit. Backups no longer overwrite each other, no longer write a near-identical copy every time the app is reopened from the dock, and no longer prune to a guessed retention count when the settings file cannot be read; the check that decides whether a file is an existing portfolio stopped reading "I could not open that" as "there is nothing there".

0.47: Every model at a glance, one model in full

A target model is the shape your accounts rebalance toward, and the page that holds them asked you to scroll a library to find one and then click twice more to reach a ticker inside it. The 0.47 line rebuilds it end to end: every model you own on one comparable table, and one model at a time built full width.

0.47.1: a percentage reads as a percentage. A model built from your holdings rounds each slice to a tenth of a percent, and the arithmetic that did it stored values like 4.1000000000000005 where it meant 4.1. The editor printed every digit. Derived models now record the number the rounding meant, and percentage fields show the value instead of the way a computer happens to store it. Anything saved by an earlier version displays correctly and is tidied the next time you save that model. The difference was never large enough to move a target, an order, or a model's completeness.

Target Models now opens on a table of every model you own. Each row draws its allocation on the same 0–100% track, so shapes compare straight down the column, beside its stock/bond split, its allocation status and total, the version in force, the accounts pointing at it and its rebalance schedule. Sort by model, status or use. Search finds a model by its name, by any ticker inside it, or by any account assigned to it. Filter chips count All / In use / Available / Needs review, and under All nothing is hidden. The groups the old list stacked models under became those counted filters: what were Household models and Ready library now read In use and Available. The library table that used to sit below the editor is gone, and so is the inert 1 → 2 → 3 strip that never advanced.

Open a row and that model is built full width, with its funds inside the slice they fill. Open a slice and you are already editing it. There is no third column, no separate fund pane, no clicking twice to reach a ticker. Every percentage is editable where you read it, collapsed or expanded: a slice's share of the model in its row, and each fund's share of that slice on its own line, with what that comes to across the whole model computed beside it. A slice filled by one fund is simply locked at 100%. The Simple / Advanced toggle is gone with the column it was hiding. Every control the Advanced face had is now just there. (Setting up a new account is unchanged: its guided model step still leads with the simple version.)

The allocation is drawn as a ring, and it never rounds itself up. A model that only adds up to 92% shows the missing 8% as a grey gap instead of stretching its wedges to look finished. It needs no legend beside it. The slice list below names every wedge, in the same order, with the same percentage.

One header says what matters and stops there. Who the model is, which version your edits land in, and what it looks like sit side by side across a single band: the name with a Valid · 100% chip or an amber Review · 97% chip that moves as you edit rather than describing what was last saved, two quiet lines naming who follows the model and how often it rebalances, the version control, and the allocation ring. Then the slices, straight away. Where the page names accounts it now links to Accounts, where a target or reference assignment is actually changed, instead of leaving you to go find them.

A model's versions are one pull-down, not a disclosure you had to know to open. The control says which version your edits save into and what it is: ✓ Effective today, Scheduled with a 2026-09-30 start, or Historical and read-only. Open it and the whole history is there, newest first, scheduled versions above the one in force and a History divider above the past ones; a quarterly cadence builds up twenty-odd versions in two years and they all fit. Rename, redate and delete sit in a beside the control, acting on the version shown. Add version starts from your most recent one by default and says what that carries before you commit (10 slices · 10 funds carried over), because a version records what changed. And when the version you are editing is not the one your accounts follow, the page says so and names the one they do.

A past version now opens read-only. Its weights are what backtests replay from that date, so the page no longer warns you about editing it and then lets you: the percentages and tickers are simply shut, while everything stays legible to read. One action, Correct this version, unlocks that one version when a recorded number really is wrong. It says plainly that saving will rewrite backtest history. Scheduled versions open editable; they haven't happened yet.

Edits are one decision. Change as many slices and funds as you like; the bar at the foot of the page counts what differs and Save model changes commits all of it at once, so your model is never briefly stuck at 92% halfway through. Discard puts everything back. Leaving for another page and returning finds your work still there; switching to a different model or version asks first. An unfinished model saves, too. Slices that don't add up to 100% yet, or a slice with no funds in it, no longer stop you. The model simply reads Review until you finish it.

Everything rare moved into a details card beside the slice: its name, the category the Screener matches funds against, its classification, each fund's reference symbol, its notes and its type. Everything about a slice except its percentages, in other words. Those stay in the list. The list slides over to make room rather than being covered, so an open card never hides the running total it is being judged against, and a quiet line under a slice's funds says what the card holds.

"Backtest reference" is now "Reference symbol." The field's first job is to say what a slice is modeled on, such as the advisor-only fund you hold a public equivalent of. Standing in for it in a backtest is what that fact then gets used for. Naming it after the use hid the fact. Searching help for the old name still finds the topic.

A slice can carry notes. If you have been keeping models a while, some of yours are already in there. The field has existed in the database for a long time and nothing has ever shown it, so notes saved by older versions of the app have been sitting unread. Open a slice's details card and they are there, editable, alongside everything else about it. Nothing in the app computes from a note.

You can also say what kind of thing a slice is. Every slice is one of three: Fund-based, the ordinary kind, whose named funds become rebalancing trades by ticker; a T-bill/CD ladder, which counts every Treasury and CD you hold and keeps working as rungs mature and roll; or Self-directed, a target size filled by your own picks, tracked in aggregate so nothing tells you to trim a winner to top up a laggard. The last two already existed. A model derived from an account holding individual stocks has always produced one, but nothing in the editor could create, change or undo them. Now the details card asks, in three lines that each say what the kind means, and says what changing it costs.

The Screener asks the comparison question first: All funds, or Funds for a slice. Model, slice and universe appear only in slice mode, which opens on a real slice, so the universe choices are never a greyed-out decoration. The universes now say what they contain: Saved funds · currently fill this slice, Same category · alternatives that fit, and All funds · no restriction. The shortlist also states whether Classic score across the whole universe or Peer score within one category ordered it, with Scoring rules one click away for whichever score is doing the ranking.

The app is easier to get around, and says where you are. While a sample is open the topbar chip reads Sample: {name} in gold, with Back to my portfolio and Switch sample… in its menu. Until now it said "Local portfolio" the whole time a demo household's numbers were on screen. The command palette (⌘K) carries the actions the shell has no room for: load any bundled sample by name, Back to my portfolio, Back up now, Projection scenarios… and Check for updates. Files & backups can be linked to by section, so Sample portfolios and Backups are one click from a menu, a command or a pasted link. A "Just exploring?" prompt on the Dashboard offers the samples to anyone who has not added an account yet. And every sample's card is now checked against the database it opens. The models it names, the age and balance it quotes and the features it advertises are verified against the shipped sample, so a card and its household cannot drift apart.

"Sample scenarios" are now "Sample portfolios." A scenario goes back to meaning one saved set of retirement assumptions inside whatever portfolio is open; a sample portfolio is a whole demo household. Old searches for the former name still find the topic, and Projection's control now reads Scenario: {name}, so a loaded plan's name is not mistaken for a heading.

Projection's three return models are named for what they answer, not for their distributions: Forward · Baseline, Forward · Fat tails and Historical replay. The names appear in the plan strip, the model cards, the Assumptions legend, the affordability table and the settings line under it. The Tail df (Student-t) control keeps its technical name, help still finds the methodology under the old names, and no projected number changed.

Fixed. Model Backtest's list cut off the part of a model's name that identified it. Names in a family share a long prefix and differ only at the tail, so a sample's list read as several checkboxes beside one name; they wrap to two lines now. The Screener's universe labels no longer spill across their neighbours or clip at the panel edge on smaller windows. And the Screener could be left in Funds for a slice with nothing to show after the last target model was deleted from another page; it now falls back to All funds and restores your choice when a model comes back.

0.46: Decisions first, details when you need them

The 0.46 line puts decisions and recovery paths ahead of setup detail while keeping the app's local-data and read-only boundaries explicit.

0.46.4: explore one coherent household at a time. Files & backups now offers four editable life-stage samples: Early career, Mid career, Near retirement, and In retirement, plus a separate Federal employee · TSP specialty sample after onboarding. Each opens a working copy, so exploring models, scenarios, contributions, withdrawals, and rebalancing never replaces your own portfolio. The retirement sample includes a 15-rung Treasury ladder inside its rollover IRA; the federal sample uses periodic snapshots and clearly labels its generated history.

The first-launch and browser-preview portfolio is now the age-63/61 near-retirement household. Its accounts, target and reference models, saved no-conversion and bracket-fill scenarios, comparison-fund research, and tax-lot history tell one consistent story across Dashboard, Projection, Screener, and Optimize. Generated dates share one fixed boundary, so model timing, research windows, withdrawal reserves, and tax-lot age do not change merely because you open the sample later.

Reserved TSP:* funds are locked to the official TSP price-history lane. Ticker Metadata explains that routing and cannot redirect those symbols to Yahoo Finance, Tiingo, or local $1 history, even if an older database contains stale source settings.

0.46.3: account setup starts with facts you can verify. Add account is now a consistent three-step flow: identify the account, choose its starting data, then review everything before it is created. You can add the real institution name from the statement without claiming the app has a connection or importer for it. Brokerage accounts can be registered Joint when both Profile people exist; retirement, HSA, and 529 accounts remain individually owned.

The cash question now asks for the current core cash vehicle on the latest statement, not one the account used years ago. Choose a known vehicle, add another money-market fund inline, select a regular cash balance, or say you are not sure yet. If an import detects a former vehicle and change date, it presents that history for review rather than changing the account silently. Once confirmed, every dated vehicle remains part of one core-cash pool, so the transition is not mistaken for new money or a trade and later activity on the former vehicle still reconciles.

Starting data is explicit too: import complete history, enter an opening statement, use periodic snapshots, or create the account with no data yet. Complete history may start at exactly $0; a deliberate zero now counts as real opening information. Review is the only save point, so an error cannot leave behind half an account, and target-model guidance waits until the new account exists.

0.46.1–0.46.2: charts can show the per-year rate. The chart above the tearsheet gained a third y-axis mode beside $ and %: %/yr draws the annualized return at every date rather than only at the end, so a model that won on one early stretch shows its lead decaying toward the pack instead of looking permanent. Its final point is the CAGR the table reports. A partial year is never annualized. Three months of +8% is not +36%/yr, so that curve starts a year into the window. The toggle disables itself, with its reason, on any shorter window. The drawdown track underneath is unchanged: it still measures real declines from the true window start. The vs benchmark picker also gained an Edit link that opens whichever list feeds your current pick: your models on Target Models, or the comparison-ticker list in Settings → Charts.

In 0.46.2 the Dashboard's Portfolio Value chart gained the same option: TWR %/yr sits beside Value and TWR %, drawing your time-weighted return as the per-year rate it compounded at, ending on the figure the Performance card reports. It follows the same one-year rule and the benchmark overlay annualizes with it.

The app now leads with the job. The permanent rail groups work under Today, Portfolio, Research, and Plan, while system destinations live in a visible Utilities menu. Global search, truthful status, Help, and price maintenance share a compact top bar. Public links, back/forward behavior, and saved page addresses are unchanged.

Rebalancing starts with the orders. Add, Reduce, Close, and cash-deployment rows lead; Holds stay one click away. A compact summary names turnover, closures, cash, and whether tax evidence is complete. Account identity and the actual order stay readable at the minimum window width, and every row has a keyboard-reachable review path. Missing account flags, model assignment, executable allocation, holdings or price data now produce one honest recovery route instead of a blank table, a false amount error or an on-target claim. A problem in one account no longer hides trustworthy orders, summaries or Biggest Moves for the others, and the visible-orders export names what was excluded. The withdrawal funding-orders export carries the same exclusion record. Dashboard accounts outside the calculation now say not rebalanced, while setup-needed reasons remain available without a mouse. Uninvested cash down to the cent now has one consistent Deploy state instead of a no-order message or a rounded-down $0 action. The action-first filter keeps following live rows until you intentionally change it, then preserves your selection for the session.

Research reads as a connected decision. Target Models separates the version you are editing from the version effective today. Optimize moves through objective, candidate rules, then run/verify/apply, and Apply stays locked until the exact proposal has comparison evidence. Its reviewed swaps now save together or none do. The Screener leads with a model-and-slice shortlist; advanced filters and columns remain available without crowding the default path. Optimize and Model Backtest now send incomplete allocations directly to Target Models instead of stopping at a dead end. Optimize failures stay visible outside Advanced, move into view, and preserve the proposal for retry. Existing Screener layouts migrate to the new ranking view with Classic score visible while keeping compatible sort and column choices.

Attention and administration are quieter. The Dashboard groups only checks it can prove from stored data. Dismissing a possible split now hides only that exact database-and-evidence candidate for 180 days; changed evidence or another database's candidate still appears, and no portfolio path is saved in the local dismissal. Settings, Profile, Help, and About now expose clearer ownership, recovery, and trust paths. Shared tables, menus, tabs, and dialogs have explicit keyboard/focus behavior, and the refreshed light and dark tokens preserve readable contrast.

Empty history now has an honest next step. Value-chart language covers Tiingo, Yahoo, and local/manual history without assuming a provider. The Ticker Metadata history drawer can rebuild one eligible ticker, or route to that ticker's exact setup, consent, or License prerequisite without bypassing it.

The trial boundary is enforced where writes happen. An expired commercial trial can still view, report, export, recover data, manage the license, and turn connections off. Portfolio, planning, import, model, and price mutations are blocked in Electron main even if a renderer control is bypassed.

Local recovery no longer mistakes uncertainty for a reset or an expired trial. If the app's configuration file is malformed or temporarily unreadable, unrelated settings and background update work refuse to replace it with defaults. Portfolio data remains readable while protected changes stay paused, and the License panel offers a retry without saying the trial ended. A retained legacy disclaimer row also cannot accept a newer version of the legal text on your behalf; changed terms are shown again when consent really needs renewing.

The bundled demo now has one honest clock. Browser-preview generation and versioned screenshot captures evaluate accrued fixed income and quote age at the sample's declared as-of date, so rebuilding on another day does not change the generated portfolio or create a growing stale-price warning. Capture captions keep the real demo date visible; sample database values were not moved forward to look current.

Dashboard performance was measured before the RC freeze. On a 1.11 GB portfolio database, the suspected repeated opening-review ledger reads totaled about 2 ms against roughly 2.2 seconds of database reconstruction, so the release does not add a speculative cache or new invalidation behavior where the measurement did not justify it.

0.45: The stocks you own, taken seriously

This app is built around funds, and it showed. A single company arrived classified as far as a fund concept could carry it and then stopped: where a fund names its category, a stock showed nothing or, worse, showed Unknown forever. The odd part is that the answer was already arriving. Every profile fetch pulls a company's sector, its industry, and the handful of figures a stock is actually judged on, and this app read the two it could use for placement and dropped the rest on the floor.

The 0.45 line picks them up. Nothing here costs an extra download.

Sector and industry, kept. A stock now carries the thing a fund's category carries: what it is. Sector is a column on Ticker Metadata with the industry on the hover, a pair of fields in the ticker editor when the feed's answer needs correcting, and a filter on the Screener beside Subcategory, which until now was an empty dropdown for anyone screening single names. Screener views you saved before this release still apply; they simply carry no sector filter.

The figures, in the row. Expanding an individual stock on Holdings now shows market cap, P/E, dividend yield and rate, beta, the 52-week range and the next earnings date, above its transactions. Read them as a snapshot, not a ticker tape: they are what the last profile fetch returned, stamped with that date and labelled underneath. This app holds one download at a time on purpose and is not about to start making a request per stock per screen. Where the feed had no answer you get a blank rather than a zero, because for a P/E those are not the same claim.

A Stock Monitor on the Dashboard. One panel for the individual names in the accounts you're looking at: the day's move, how far each sits below its 52-week high, what share of your equity it is, and three flags: a position over your concentration threshold, a close within 5% of the 52-week low, earnings inside 60 days. The threshold is yours to set, on the panel, and it stays set. Concentration is measured against your equity rather than the whole portfolio, since "8% of my stocks" is the question a concentration flag exists to answer. The panel is computed entirely from closes already on your machine, so it costs nothing to open. That is also why the day's move reads the same all weekend. A portfolio of nothing but funds never sees it.

"Unknown" is gone. A stock imported from a broker CSV was stamped with that placeholder category, and because a single company has no fund category, no amount of re-fetching ever cleared it. An AAPL row read Stock · Equity · U.S. · Unknown indefinitely. Upgrading corrects those rows once. A category you typed yourself is left exactly as you typed it.

An AI you connect can see sectors too. get_accounts_and_holdings now reports sector and industry beside category, and says which to read for which kind of holding: a fund has one, a stock the other, and a blank on either side is normal rather than missing data. The stats above are deliberately not exposed: they are a snapshot whose staleness a caller can't see, and an assistant quoting a fortnight-old P/E as today's would be worse than one that never had it.

Also in this line. The model-lens help claimed holdings were placed by sector. They never were. Placement reads market cap and country, and that sentence now says what the code does.

0.45.1: a fund that got filed as a stock

The feed sometimes answers for a newly listed ETF as though it were a company: no category, no expense ratio, type "equity". One of those answers was enough to store SPYM, a $161B S&P 500 fund, as a Stock, which then put it in the Stock Monitor above as if you held a single name. Setting Security type back to ETF by hand didn't survive either, because Type was the one field a fetch rewrote outright while everything else was merged.

A category or an expense ratio now outranks that answer because a company has neither. The app reads them from the fetch or from what it already recorded, since a bad answer drops the category too. Anything already mis-filed is repaired by its next fetch. The trade-off is worth stating: a stock carrying a category you typed yourself now reads as a fund, so clear its Category if you mean stock.

0.44: Backtests for your AI, and a second way in

The 0.43 line settled which AI answers. The 0.44 line is about what it can do once it does, starting with the thing it most obviously couldn't.

It can test a model, not just suggest one. Ask your assistant to compare a draft allocation against the one it would replace, or against the models you already keep, and it replays them over the price history this app has already downloaded, using the same engine the Model Backtest page runs. Up to four at once, on purpose: run together they share one window, so the comparison is measured over the years all of them actually cover instead of flattering whichever had the kindest decade. It downloads nothing; it reads what you already have. It is honest about the gaps. A saved model holding a fund with no price history says so, and a proposed one naming such a fund is refused rather than quietly counted as cash, which would have rigged the very comparison you asked for.

Answers are formatted. Sections, bullets, bold on the number that matters, and a real table when the assistant is comparing figures, which is most of what this pane is for. Before, a comparison arrived as asterisks and pipe characters. The pane renders light formatting only: a model that reaches for something more elaborate, like a list inside a list, gets flattened rather than mangled.

It can tell you which switch to flip. With projections switched off, the assistant used to say it "doesn't have access." That was true, useless, and indistinguishable from a broken app. It is now told which row in Settings → AI assistant turns that tool back on, and told to point at it rather than estimate the answer by hand. Whether it takes the advice is the model's to get right; what changed is that it is no longer guessing in the dark.

Model names can be picked, not typed. Every model field now fetches the list from the source itself: the models your LM Studio has loaded, the current Claude and DeepSeek line-ups, whatever your own server offers. Typing a name the app has never heard of still works. Claude also gains the priced Opus/Sonnet/Haiku picker in Settings that DeepSeek already had.

And a running total of what it has cost. Under the per-conversation line, a second line adds up every turn this copy of the app has run, across every source, surviving Clear and a restart. Each turn is priced at the model that actually answered. It is kept beside the app's own settings, not in your portfolio file, so it never rides a backup.

A second way to connect a client

Most AI clients launch the connector themselves. A few can only be pointed at a web address, so there is now a switch for that, off unless you turn it on. It serves the same tools at an address on this computer, behind an access token the app generates for you to paste into the client, with Regenerate if you ever think the token has been seen. The panel now says which door each connected client came in by.

Under it sits a second switch, also off, that opens that address to other devices on your network, such as the desktop in the other room, a laptop, or a phone. It carries what it costs, in plain words: the connection is unencrypted, so anyone on the network path can read your portfolio and the token, and it opens on every network the computer is attached to rather than only the one you had in mind. The panel lists the addresses it finds and warns if one of them is reachable from the internet. If you want the app from somewhere else, an SSH tunnel does the same job encrypted, and AI assistant access shows the one line that sets it up.

One more thing about that switch: it lives in your portfolio file, so restoring a backup taken while it was on used to re-open the port with nobody clicking. Now the app asks every time a portfolio arrives from a backup, a sample, or another machine, and Turn it off is the answer sitting under your fingers.

Also in this line. The About page's privacy sentence now names its one exception instead of promising more than the app can keep once you switch an AI feature on. And the file holding your license and price-data keys is written whole rather than in place, so a crash mid-write can't leave it truncated.

0.43: Four AI sources, by name

The 0.42 line gave this app an assistant. The 0.43 line is about which AI answers it and about not having to know a base URL to say so.

The sources have names now. Settings → AI assistant offers four: Claude, DeepSeek, LM Studio, and Other server for anything else that speaks the same protocol. Before, the choice was between "Anthropic API" and "Custom endpoint", which meant knowing which address DeepSeek answers at and which LM Studio setting reaches a second machine. Each source now asks for what it actually needs and nothing else.

DeepSeek. A key from platform.deepseek.com and a choice of two models: Flash, fast and very cheap, or Pro, which reasons longer on harder questions. No address to enter. Both are priced in the app, so a DeepSeek answer carries the same per-turn cost line a Claude answer does; a sweep that costs cents on Claude usually costs a fraction of one here.

LM Studio, on this computer or the one down the hall. Locally, the address is already filled in: start the server in LM Studio's Developer tab, name the loaded model, and you're done. On another machine, such as the desktop with the real GPU, switch on Serve on Local Network in that copy of LM Studio and enter the address it shows you. There is no key to invent, because LM Studio's server doesn't use one.

As many as you like, at the same time. Claude, DeepSeek and a machine on your network each keep their own settings and their own encrypted key, so setting one up never disturbs another. Settings names which ones are ready, and once two are, the Assistant page grows a switcher in its header. One click asks the same question of a different model. Switching starts a fresh conversation, because the services don't speak a common format mid-thread.

And the panel tells the truth about your network. Pointing the assistant at another machine in your own house is a normal thing to do, and it now reads as one: what it reads goes to that machine over your network, not out to the internet. Previously every address that wasn't this computer got the same warning, which told people doing it right that they were doing something wrong. On this computer it still says what it always did: nothing leaves at all. An address out on the internet still says exactly where your data would go.

Nothing about permissions changed. Reading is on whenever an assistant is; projections and model proposals are each still their own switch, they still govern both doors, and nothing is saved to your portfolio without your approval in the app.

0.43.1: a full review pass, and one bug worth knowing about

The most consequential fix: under VPW or % of balance, the projection could treat a still-working plan as already retired. Those two strategies read your remaining balance directly, and the age they started reading it from was your current age rather than your planned retirement age. A 50-year-old aiming to retire at 65 could see the engine prescribe retirement-scale withdrawals through fifteen years that should have been building the portfolio, not spending it. A sample $1M plan under VPW read roughly $1.48M at 64 where the corrected math reaches $2.60M. The same gate now applies everywhere that family of numbers is read: the strategy-comparison table, a future home purchase's ongoing costs, and the sustainable-withdrawal-rate reading, which also now counts the tax bill due on every withdrawal rather than only the withdrawal itself. If you run a balance-driven strategy on a plan that hasn't retired yet, it's worth opening Projection again. The numbers you saw before this release may have understated what your plan actually supports.

The rest of the pass was a full code review, not a single feature: it closed data- integrity gaps (deleting a ticker could, in three specific situations, silently break a snapshot-tracked account, a matured CD, or a sweep fund's cash tracking), stability gaps (a dead price sidecar could crash the app; a stalled price server could hang a fetch with no timeout), a cost-basis ordering bug on same-day buy/sell pairs, several pages that could get stuck at "loading…" after a rejected request with no way to retry, and a round of smaller interface fixes. The full list is in CHANGELOG.md.

0.42: An AI that can read your plan, and propose to it

The 0.42 line opens this app to an AI, one that answers from your numbers instead of generalities, and that can hand you a target model without ever being able to save one behind your back.

Your questions, answered against your own plan. The projection engine has always been able to answer "what if I retire at 65?", but only for one scenario at a time, typed in by hand. Now an assistant can sweep it: six retirement ages, both Social Security claiming dates, a return assumption moved up and down, each run seeded so the comparisons are honest, and the differences explained in terms of your accounts. The same goes for what you hold: drift against your models, a rebalance preview, or an expense-ratio comparison, all asked in a sentence.

Two ways in, and you choose the door. Settings → AI assistant turns on a private local socket that an AI client you already run, such as Claude Desktop, Claude Code, LM Studio, or Codex, can connect to. That connection opens no network port of its own and exposes nothing to your network, and the switch is off until you turn it on. If you'd rather not configure anything outside the app, the Assistant page is the same thing with a chat pane around it: bring an Anthropic API key, or point it at a model running on your own machine through LM Studio or Ollama, in which case your portfolio never leaves your computer at all.

Connecting an outside client takes one paste. The panel prints the exact configuration for each of the four, and the connector it points at ships inside the app. There is nothing to install or keep updated, and it works the same on macOS, Windows, and Linux.

Windows note since 0.46.0: the shipped runtime does not provide a proved creator-only named-pipe boundary, so Windows no longer starts or advertises that connector. A Windows external client can use the access-token-protected web address, still behind its off-by-default switches. The macOS/Linux connector remains as described above; see AI assistant access for the current platform details.

The AI proposes; you dispose. An assistant can draft a target model, and that is the only thing it can write. The draft arrives as a card inside the app, validated to 100% and showing every ticker and weight, and nothing is saved until you press Save as model. There is no tool to delete anything, none to edit your holdings, and, as has always been true here, nothing in this app can place a trade.

You can see what it did. Every tool call an assistant makes is listed in the Settings panel as it happens, tagged with what it was allowed to do: read, compute, or propose. The three switches that grant those permissions are the whole of what a connected assistant can reach.

And the account wizard got a pass for the rough edges. Every step now says which one it is. A fund with no ticker is entered from a button beside Add ticker rather than a question above the grid, its form asks for the share count with everything else. A row missing one used to grey out Continue with nothing on screen to say why. A fund entered before is picked from a list instead of retyped, which no longer files it under a second symbol. Both that form and a target mix's slices can now name a real fund category, the thing the Screener and the exact-fit test actually read. The TSP fund picker appears only for TSP accounts, and a refused Continue or Save names what it's waiting on.

0.42.2: what one new account was doing to a finished portfolio. Adding an account could blank the Portfolio Value chart: the household chart began where every account had data, so an account added today set the start for all of them and left a single point with no line to draw. A new account now counts as nothing before it existed, and the years either side of it stay put. The setup checklist names the account it's about, in its heading and in every open step, instead of leaving four instructions with no address on them. Deleting an account now takes it off the checklist, so the bar retires itself rather than outliving what it was set up for. Opening the Assistant page no longer asks for your keychain password; it was checking whether a key could be stored in order to draw the page, and now asks only when you actually save one.

0.41: Spending that follows the portfolio, priced honestly

The 0.41 line lets your plan answer a question it previously assumed: what rule decides how much you spend each year.

Your spending can follow your plan, or follow your portfolio. Until now the projection spent exactly what your plan said, every year, through anything the market did. That describes a retiree nobody has ever met. Expenses → Spending strategy gained two alternatives beside it. VPW is the Bogleheads Variable Percentage Withdrawal: each year it spends what your remaining balance would support if spread evenly over the years to a terminal age (100 by default), at your own stock/bond mix. The percentage rises as you age, because there are fewer years left to cover, which is why spending holds up far better than a flat rule. % of balance is the simplest version of the same idea, included because it is the honest floor of the genre.

The percentages match the published Bogleheads table to the digit: 5.0% at 65 for a 60/40 portfolio and 6.9% at 80. Where your plan already describes an allocation, the mix comes from it age by age, so a glide that de-risks lowers the withdrawal percentage on its own. Social Security and pensions sit underneath the rule as guaranteed income rather than inside it, and spending never drops below the essentials you have marked fixed.

Every one of these rules is very hard to run out of money with. That is the part to be suspicious of. A rule that hands you a share of what is left can never hand you nothing. The failure doesn't disappear; it moves into your spending. So nothing here reports a success rate on its own. Explore → Compare spending strategies runs your household under every rule on the same seed and the same market years, and puts both halves in the same row: the chance of success and the depletion age, next to the leanest year you would actually be living on, how many years spending ran below plan, and what was left unspent at the end.

On the sample household's saved plan, VPW turns a 13% plan into a 100% plan. It does so by paying \$46,097 in the worst year of a bad decade, against a plan that called for \$88,000. Both numbers are on screen, together. Which of them matters more is a question about your life, not your spreadsheet.

The spending guardrail was under-counting its own cuts. Its honesty report compared each year's spending, including the Medicare premium the app works out for you, against your planned spending, which doesn't. With Medicare modeled, a real trim could vanish behind the premium added on top: a 10% cut to a \$40,000 flexible budget read as no cut at all beside a \$5,000 premium. The report now compares like with like, so its cut years and their depth are the real ones. Plans without Medicare modeled are unaffected. Only one rule ever drives your spending. Two reacting to the same signal would double up, and you could no longer tell which one moved your spending.

0.41.1: the withdrawal-rate check stops grading a rule it can't grade. The safe ceiling on the Withdrawal rate by age chart is the highest fixed real draw that survived history. That's a sensible bar for a plan that spends the same amount every year, and the wrong bar for VPW, whose percentage is meant to climb as the years left shrink, so a perfectly healthy VPW plan read as permanently reckless, its line above the ceiling from the first year to the last. With a balance-driven strategy active the ceiling and the green/amber/red grade both come off, and the chart says why. The rate curve stays: it still describes what you're drawing. Under the standard spending plan, nothing changes.

A comparison row no longer reads as a contradiction. "97.6% · runs out at 93" raised the obvious question: which is it? That age was only ever the median among the paths that did fail, so the row now names them: 97.6% · 2.4% fail, typically at 93.

The year-by-year table reads like a statement instead of a wall. Its columns now run in the order a year actually happens, under headings that say so. First comes what you hold at the start, with Value beside the bucket balances it sums. Then come what goes out, what funded it, and what moved into accounts. Columns with no activity anywhere in your plan are hidden and listed underneath, so a household with no Roth or no HSA stops scrolling past thirty rows of $0 (hidden means all-zero, not unmodeled; a column returns the moment your plan uses it). The Age column stays pinned while the rest scrolls sideways.

0.41.2: the year-by-year Spend column showed the plan you typed, not what your plan actually spent. It read the spending schedule straight off your inputs. Under the standard spending plan those are the same number, so it was right by coincidence. A spending policy exists precisely to move spending away from the schedule. Under VPW the column was simply the wrong number: it sat flat for decades while every balance beside it fell, which is the opposite of what VPW does. Under the guardrail it hid the cuts for the same reason.

Spend is now what the plan actually spent, from the engine, with Medicare beside it rather than inside it. When a policy has moved spending off the schedule a Plan column appears next to it, so you can read the gap year by year. That gap is the strategy working. Under a plain spending plan the column stays hidden, since it would only repeat Spend. The terminal age is blank because no year is simulated at it.

0.41.3: one picker for how much you spend. The guardrail used to be a separate panel with its own checkbox, sitting beside the strategy picker as if it were a modifier you bolted on. It isn't. It is the second rung of one ladder, from spending that never reacts to spending that is entirely whatever the balance says. It now sits in that ladder, as one of four options in Expenses → Spending strategy: Fixed plan · Guardrail · VPW · % of balance. Picking one rules out the others, so there is no longer a combination of controls to reason about. ("Spending plan" is now called Fixed plan, which is what the rest of the app already called it.)

Your settings are untouched. A plan that had the guardrail switched on opens on Guardrail with the same knobs; one that didn't opens on Fixed plan. Every saved scenario loads exactly as it ran, and switching rules to look around never loses the posture you configured.

The flexible share of your spending moved out where you can see it. That one field, which says how much of your everyday budget you could actually cut, was buried inside the guardrail's panel, which meant VPW and % of balance quietly used it without ever showing it to you. It is the same number from both directions: the slice the guardrail trims, and the essential floor a balance rule can never take you below. It now sits under the picker for all three rules that need it.

Explore → Compare spending strategies gained a fourth row, so the guardrail is priced beside the others on the same seed and with your own knobs, whichever rule you currently have picked. That table's Fixed plan row is also genuinely fixed now: with the guardrail switched on it had been quietly running with it, which made the baseline every other row was compared against the wrong one.

0.41.4: account setup that ends where it should, matching your broker. Setting up an account from a CSV import had every mechanical piece and no recipe, and the visible symptom was importing a file and staring at negative shares. The wizard's import path now asks one question: track this account from when?, usually the 1st of a month. It derives everything else: enter holdings and cash from the statement dated the day before (the entry locks to that date, and each position can carry its cost basis straight off the statement, so gains match your broker's from day one), then export transactions from the start date onward. Rows on or before the statement date are skipped on import, so the two sources can never double-count. The full recipe is in the guide.

The import dialog now finishes the job: it names the exact date to export from, flags a file that starts months after your opening date before you import it, detects missing opening cash the same way it already detected missing positions (the pre-filled figure is the minimum your ledger proves; correct it against the statement), and hands you to Compare with broker at the end. And if negative shares do appear on Holdings, they now come with a banner saying what they mean and where the fix is, instead of unexplained red numbers.

0.41.5: your model's history was always the feature; now you can see it. A target model isn't one allocation, it's a series of dated versions, and Model Backtest has always replayed them in order. You could just never watch it happen: every bundled model carried a single version, so the version markers and change tooltips already built into the chart had nothing to mark. The sample 60/40 now carries the history its own note always claimed: 70/30 from 2020, de-risked to 60/40 in January 2024. The switch lands mid-chart and you can see what changing an allocation actually did to the curve.

Extend back now starts at Max. Off sounded careful and behaved like a wall. A model's first version dates from when you recorded the allocation, not when you started holding it, so a model built this morning drew a one-day chart. The setting that fixed it was three levels deep. Now the stretch before your first recorded version is drawn as a dashed line running up to the version marker, so the "this part is extrapolated" disclosure lives in the curve where you're already looking. When a window is genuinely too short to plot, you get a plain statement of why and a one-click fix instead of an empty chart.

How the app works is a new topic for a loop the app never narrated: what you own and which parts of the app read it. It opens the Help centre and anchors the Projection page's empty state.

A self-directed slice can be turned off again and can no longer swallow the funds beside it. Marking a slice self-directed tells the rebalancer to size it as one lump and leave your individual picks alone, which is exactly what some people want for a satellite sleeve. But only one path could ever set that flag, nothing could clear it, and the slice editor would happily let you add funds to a slice whose funds rebalancing then ignored. A 25% "My picks" slice could list five tickers in Target Models while Rebalancing showed a single unnamed row mentioning none of them. There's now a toggle in the slice editor, and the contradiction is gone for good: a self-directed slice can't hold funds at all, the form says so and names anything a save would drop, and the slice list reads Your own holdings, the same words the Rebalancing table already used.

A salary typed with a comma modeled as no salary at all. Every money field on the Projection page read "103,001" as unparseable and quietly used zero. As a result, a typed salary meant no contributions in the engine, a flat Work band in the income chart, and nothing on screen to say anything was wrong. Pensions, annuities and passive income had the same hole. Commas, dollar signs and stray spaces are now accepted everywhere the rest of the app already accepted them. On the household this was found in, it's the difference between an 81.0% and an 82.5% plan. The projection had been modeling an unemployed year.

A VPW terminal age inside your plan's horizon zeroed every statistic, and nothing said why. Set the terminal age to 95 with your plan running to 95 and all three success numbers read 0%. The engine is right, and the reason is worth knowing: VPW amortizes your portfolio to zero at the terminal age, so the final year draws 100% of the balance. The taxes and Medicare that come due after that draw have nothing left to come from, which marks every path as failed no matter what markets did. The panel now warns as soon as the terminal age reaches your plan's horizon, names both ages, and tells you to set it higher. It stays a warning rather than silently correcting the number: the projection keeps modeling exactly what you typed.

0.41.6: a first user's notes

Everything in this update came from one person's list after a week with the app, which is the most useful thing anyone has sent.

The model wizard's Review button did nothing on nine of the fifteen ready-made Schwab mixes. Pick a published mix, look over its slices, click Review. Nothing happened, with nothing on screen to say why; the only way to assign a model was the account settings form. The button was refusing the click rather than dropping it, and three things hid that. The ready-made mixes work out each fund's share of its slice by rounding, which can leave a slice's funds totalling 100.01% instead of 100%; the check behind the button rejected exactly that hundredth; and a disabled button looked exactly like a live one, sitting beside a hint asking for a total of 100% next to a total already reading 100.00%. The check now tolerates rounding, the ready-made mixes land exactly on 100%, a button you can't press looks like one, and where a mix really is unfinished the hint names the slice at fault and offers to open it.

The backtest's metrics explain themselves. The Strengths and Trade-offs cards hand you a verdict in words nobody is born knowing, such as Best Sortino or Lowest Ulcer Index, and used to explain none of them. Hover any bullet for its definition, or open Reading the backtest metrics from the panel: which number answers which question, and why two of them disagreeing is usually the finding rather than a contradiction. Seven entries sit behind it: CAGR, volatility, max drawdown, Sharpe, Sortino, Calmar and the Ulcer Index. Each is findable by name from ⌘K.

Two smaller things on the same page. Long model names were cut off in the list with no way to read them, and because every ready-made name starts with the same family, the part that got cut was the ratio telling them apart. Hovering a row now shows the whole name. And a blank chart used to blame the timeframe when the real problem was that a model's funds had never been priced: funds are registered when a model is, but prices are downloaded separately, so the app now names the funds it has no prices for instead of pointing at a date control that was never the cause.

Copies of a model are no longer joined to the original. One report said "cloned models seem to be linked; if you change a parameter in the cloned one it changes the original." It turned out to be two separate bugs wearing the same description, and both quietly rewrote a model you weren't looking at.

On Target Models, duplicating always made a real, independent copy; the trouble was the editor beside it. The slice editor is attached to one model's rows, and Duplicate selects the new copy without closing it, so the list and heading switched to the copy while the open form stayed attached to the model you copied from, and saving rewrote that one. The same happened on any switch: clicking another model, or another dated version, with a slice still open. The editor now closes whenever you change model or version, so what you save is the thing on screen. If you duplicated a model and edited the copy before this release, it is worth checking the original. The change may have landed there.

In account setup, the mix picker invites you to start from a ready-made mix and change it. The change went into that published mix, and into every other account already running it. Now your first change makes your own copy, named for the account you are setting up: the ready-made mix stays as published, other accounts keep the target they had, and the editor tells you the copy was made. Pick a mix and change nothing and no copy appears, so several accounts can still share one mix on purpose.

0.40: Cash that counts, and crashes that stay put

The 0.40 line fixes a model slice that could never be satisfied, stops one broken page taking the window with it, and makes the destructive actions say what they actually do.

A model can hold cash, and the cash row finally reads it. A slice written with the reserved $CASH ticker reported $0 held forever, while the same dollars sat in the account inflating the pie. As a result, Rebalancing kept telling you to buy cash the account already had, counted twice against Deploy, on a slice that could never close. It reached the 15 Schwab models the empty starter seeds and any model imported from CSV. The Deploy row and the cash row are one thing now: state a cash target in your model and the row targets it; state none and nothing changes, with uninvested cash still always flagged.

One page hitting an error no longer takes the window with it. Each page now has its own named error card with a retry, so the sidebar, the banners and the other pages stay usable while one is broken, and the fault is on screen instead of leaving you a white window and nothing to report.

Restoring a backup asks you to type the phrase, and its safety net is real. Restore replaces your live database, but it was the one such action with a two-button confirm under copy claiming it "cannot be undone." A pre-restore snapshot was being kept all along, as a hidden file no screen mentioned. It now asks you to type RESTORE <backup name>, tells you the snapshot exists, and files it in the Files backups list where you can find and restore it. Back Up Now from the File menu lands there too, instead of reporting into a dialog the page never saw.

Recording a split confirms where you found it. The action sits under the banner that raised the flag, so the preview and the decision sit together. The copy now names both sides: it scales pre-split share counts and leaves current shares, cost basis, transactions and downloaded prices alone.

0.40.1: your license says how long updates are included. An activated copy showed only who it was licensed to, while the key on disk already carried the date. Settings → License now reads it off your own key: updates included through August 3, 2027. Once that day passes, what still works and what a renewal would pick up. Nothing about the app changes when the window closes: your license stays valid, every version you already have keeps working, prices still update and imports still work. What lapses is only your claim on newer builds, and it is never checked while you work. A license bought before this model existed carries no date at all and is perpetual, covering every version forever. It shows who the copy is licensed to and says nothing about updates.

The License panel says each state once. It restated one fact up to three times. Every state is now one line for what's true and one for what it means, including what a license actually includes: a year of updates, with every version you already have working for good afterwards, verified on your computer. A lapsed trial strip also gains a direct Buy a license exit, and an activated copy keeps a Replace license key box so an upgrade key needs no removal first.

Signed numbers agree with each other now. A value too small to print at the precision shown no longer keeps its sign, so nothing reads "−0.0%" or "−$0" when the answer is zero. And a gain or loss is written the same way everywhere: the Rebalancing drift row used a different minus for its percentage than for its dollars, and a withdrawal in a ticker's history used a different one again from the same withdrawal on the cash panel.

Some text was hard to read on gold. Buttons and chips filled with the signature gold drew their label in white, which barely showed against it. The problem was worst on the Screener's column button, the TSP fund chips and the money-flow toggles. They now use dark ink, and the expired-trial notice no longer paints a pale bar across the dark theme.

Also: one verb for every CSV control ("Export" for what's made on demand, "Download" for files that already exist), accepting the disclaimer now records which text you agreed to, a development build says so instead of claiming the network failed, and the update check's description names everything it sends: version, operating system, and a once-only first-run flag; no usage data and no identifier.

0.40.2: the update banner stopped pointing at the version you already have. When a newer build was offered, the strip carried "See what's new in …" naming your installed version, not the one on offer. A copy of the app only ever ships its own notes, so that link could never describe what the download would give you. The banner now offers the download alone. "See what's new" lives where it is true: Settings → Updates, on the line a completed check produces when nothing newer exists.

0.40.3: the samples show what to do with the TSP funds. Adding them has been one button in Settings, but nothing bundled with the app demonstrated them. Every sample now carries six priced TSP funds and the two target models a federal employee actually chooses between: TSP L 2040, the one-fund Lifecycle default, and TSP Custom Mix · 85/15: C 55 / S 20 / I 10 / F 5 / G 10. Load the mid-career sample, open Model Backtest and select both: the self-picked mix returns more over the window and gives more of it back in the drawdown, for a reason you can point at: more equity, and a quarter of the L fund's international sleeve. As everywhere else in the samples the prices are synthesized, with two things held true to the real funds: the L fund's series is the blend of the other five rather than a series of its own, so the gap between the curves is allocation and nothing else, and the G Fund never has a down day. Press Update Prices and the real published share prices replace them, which takes the comparison back to 2003.

0.39: Ways out, and a menu bar

The 0.39 line is mostly about the app being easier to leave, link to, and trust, along with the first honest menu bar it's had.

  • A way out when something's wrong. About gains Get help · Report a problem: the support page and an email link carrying your version, plus links to the site, privacy policy and terms. The same route sits at the foot of the Help center and in the Help menu.
  • A real menu bar. Settings… ⌘, · File → Import Broker CSV… / Back Up Now / Open Data Folder · Help → Help ⇧⌘/, What's New, Report a Problem…, and the product site. The native About panel finally shows the version and copyright.
  • Release notes that reach you. This panel had stopped at 0.30 under a 0.38.6 app; it now carries the current line and the two before it, and the update banner links straight here.
  • Every page has an address, such as #/holdings or #/settings?section=price-data, so the back button works, a reload returns you where you were, and Settings gains a section nav across its eight panels.

Two numbers were wrong and are now right. Until price history exists, the Dashboard's headline Total left out core cash while the projection counted it, so the app's first number disagreed with its second by exactly your cash. And the Holdings summary printed Market Value $0 over a full table for any account without a transaction ledger.

The expired-trial message overstated what you lose. It claimed a license restores exporting; exports were never gated. Your portfolio stays readable and exportable. A license restores editing and price updates.

Also: navigation regrouped by task, the two Screener scores renamed from version numbers to the Classic and Peer scores, model validity is green everywhere, wide tables show when they're clipped, and Inter now ships with the app so your install looks like the screenshots.

0.38: Housing decisions, and a benefits cut you can test

The 0.38 line went after two of the biggest levers a retirement plan has: when you buy a house, and what Social Security actually pays.

  • Stress-test a Social Security cut. Reduce both people's benefits by X% from a chosen year. The preset is 20% from 2034, based on the trust-fund depletion arithmetic. Then watch the plan absorb it. See stress-testing a cut.
  • "What if I wait?" The affordability finder now answers its natural follow-up: if you delay a year or two and those years run weak, soft, expected, firm, or strong, what's the most house from that state? Each recommendation is also scored under all three return models at once. See the affordability finder.
  • Withdrawal rate by age. Net portfolio draws as a percentage of that year's starting portfolio, plotted against the ceiling the KPI grades against.
  • A daily update check, disclosed and off-switchable. Version and operating system, no identifier, no usage data, and no exceptions on Store installs. See the About page.

Fixed along the way: a future-year home purchase no longer gets an inflation head start; a cheap house no longer carries an expensive house's upkeep (insurance and maintenance scale with price now); the withdrawal-rate chart stopped drawing guardrail thresholds that measured a different ratio than its own line; and chart legends draw dashed lines as dashed.

0.37: The projection explains itself

Two new topics and one button, all aimed at the same question: what is this number actually claiming?

  • How to read the results defines success % as a pass/fail tally (one unfunded dollar fails a run), failure depth, the median against its bands, and why per-age medians don't add up like one household's years.
  • How Social Security is modeled collects the claim-age math, the statement-vs-salary entry paths, worksheet taxation, and the survivor rule in one place.
  • Trace: zero volatility. One click zeroes every randomness input so the year-by-year table collapses to a single hand-checkable path, then restores your exact prior settings. See seeded simulations.
  • The implied compound rate now sits beside every return field ("≈ 5.8% comp."), where the number gets typed rather than in a caption below it.

Tax constants caught up with the July-2025 OBBBA: the standard deduction and the 65+ bonus deduction (modeled with its statutory sunset) had been understated, so taxed plans tick up slightly. IRMAA's two-year lookback now counts only the taxable part of Social Security, matching the real rule. A benefit-heavy plan is no longer charged a premium tier early. See what the tax model covers.

Fixed: Profile's tax-rate fields accept decimals again. Typing 4. used to snap back to 4, putting a rate like 4.4% out of reach.

0.36: A fresh install that can fetch prices

A new install had two quiet cliffs. Both are gone.

  • "Set up price data" instead of a failed download. A fresh install has neither feed ready. Tiingo is the default but needs a key, while Yahoo is an explicit opt-in, so Update Prices used to fail once per ticker with no explanation. The top-bar button now names what's missing and routes to Settings → Price data, which links out to Tiingo's signup and token pages; the Screener's unpriced-funds prompt says the same. See price sources.
  • Turning Yahoo on now makes it the default when no Tiingo key is saved. This is the rule the first-run wizard already applied. Without it, enabling Yahoo changed nothing: every unpinned ticker still routed to a keyless Tiingo and the whole sync failed.
  • The sample households are half the size. The bundled fund universe became a curated sampler. Every category is still represented, with 1,914 tickers down to 127, and seeded price history starts in 2020. Each sample file drops from 18.4 MB to 9.5 MB, so a demo's one-time price update is a job that finishes instead of one that trips a rate limiter. See the Files page.

Settings → License also gained a Buy a license link and a note that the key arrives by email and on the thank-you page. The trial banner used to land someone with no key on a form asking for one.

0.30: In-app help, everywhere

This release adds the help system you're reading right now, built in, offline, and honest about the app's modeling decisions.

  • "?" tips beside computed numbers, modeling knobs, and badges offer two sentences in place and a Learn more link for the full story. Placed deliberately: self-explanatory fields stay clean.
  • A contextual panel on every page (the top-bar "?", or ⇧⌘/ / F1) with the page's guide and related topics.
  • This Help center: guides for all 15 pages, how-the-math-works methodology, a glossary, task recipes, and troubleshooting. Over 70 topics, searchable here and from ⌘K.

Nothing about help leaves your device, and reading it never changes your data. Start with using help.

0.29: Published outlooks preset

The 0.29 line focused on making the projection's forward assumptions easier to anchor honestly:

  • Published-outlooks consensus preset: seed Forward Assumptions from a blend of published capital-market outlooks instead of hand-picked numbers, with the sources named.
  • Return-unit notes in the UI: assumption fields now say whether a figure is arithmetic or compound, because mixing the two silently biases results.
  • Fix: compound CMA estimates are converted to arithmetic before the valuation shrink is applied, so the condition-on-today drift adjustment no longer double-penalized compound inputs.