feat(calculator): add recommended filing ages card to Strategy Optimizer#571
Merged
Conversation
Surface the strategy optimizer's recommended filing age(s) as a display-only card in the calculator's Strategy Optimizer section. It computes the single best result with default assumptions (2.5% discount rate, blended life expectancy) and links into the pre-filled /strategy optimizer. - Move OptimalStrategyHeadline into $lib/components and add an optional showInfoTip prop; the calculator variant hides the tooltip and shows a short default-assumptions note instead. - Add recommended-filing-card.ts (tested logic: optimal-result compute, mortality loading, and a shared buildStrategyUrl) plus a thin RecommendedFilingCard.svelte shell that loads mortality once and recomputes on PIA changes. - Restructure StrategyPromo: header -> explanatory copy -> card -> CTA, replacing the prior PIA summary and reusing the shared buildStrategyUrl.
Deploying social-security-tools with
|
| Latest commit: |
72c6df8
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://8e39f0a7.social-security-tools.pages.dev |
| Branch Preview URL: | https://worktree-recommended-filing.social-security-tools.pages.dev |
- Guard maybeLoadDistributions against out-of-order resolution: re-check distKey after the await so a slower in-flight load can't apply stale mortality data. - Include healthMultiplier in the mortality cache key (it affects the distribution), and correct the related comments / JSDoc. - Log unexpected compute failures with console.error (the optimizer returns [] for edge cases rather than throwing, so a throw is a bug). - Add tests: single empty-distribution -> null, and that the discount rate defaults to DEFAULT_DISCOUNT_RATE when omitted.
The recommended-filing card was absent from Chromatic snapshots: - Storybook did not serve the SvelteKit `static/` dir, so the card's /data/processed/*.json life-table fetch 404'd and the card hid. Add `staticDirs: ['../static']` so the data loads. - The Full Report story fixture was born 1950 (age 76 in 2026), past the 62-70 filing window, so the optimizer had nothing to recommend. Move it to 1962 (in-window) so the card renders in the report snapshot. - Compute the first result immediately instead of behind the 250ms debounce, so the card appears as soon as the data loads (better UX) and Chromatic doesn't snapshot mid-debounce. Subsequent recomputes stay debounced.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a display-only "Recommended filing" card to the calculator's Strategy Optimizer section. It surfaces the strategy optimizer's best filing age (single) or ages (couple), computed with the optimizer's default assumptions (2.5% discount rate, blended life expectancy), and the whole card links into the pre-filled
/strategyoptimizer.The card sits inside the Strategy Optimizer block: header → short explanatory copy → card → "Open Strategy Optimizer" button. The previous PIA summary line was replaced with copy that explains what the optimizer does and what clicking through offers.
What changed
OptimalStrategyHeadlinefromroutes/strategy/components/into$lib/components/(it's now shared) and add an optionalshowInfoTipprop. The strategy page keeps the tooltip (defaulttrue); the calculator variant passesfalse, which hides the tooltip and appends a short default-assumptions note.recommended-filing-card.ts— pure, unit-tested logic: optimal-result computation (reusingexpectedNPVSingle/expectedNPVCoupleOptimized), mortality-distribution loading, and a sharedbuildStrategyUrl.RecommendedFilingCard.svelte— thin shell that loads mortality once (keyed on gender + birth year), recomputes the recommendation on PIA changes (debounced), renders nothing until a result is ready, and wraps the shared card in the optimizer link.StrategyPromo.svelteto render the card and reuse the sharedbuildStrategyUrl(removing its private duplicate). The calculator page itself is unchanged (the card lives insideStrategyPromo).Notes
OptimalStrategyHeadline.Test plan
npm run test— all 2056 tests pass, incl. 13 new tests for the logic module (compute equivalence toexpectedNPV*, exact pre-filled URL strings, mortality-load behavior).npm run quality— Biome + svelte-check clean.npm run build— all routes prerender./strategy, and updates when earnings/PIA change.