Skip to content

feat(calculator): add recommended filing ages card to Strategy Optimizer#571

Merged
Gregable merged 3 commits into
mainfrom
worktree-recommended-filing-card
Jun 22, 2026
Merged

feat(calculator): add recommended filing ages card to Strategy Optimizer#571
Gregable merged 3 commits into
mainfrom
worktree-recommended-filing-card

Conversation

@Gregable

Copy link
Copy Markdown
Owner

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 /strategy optimizer.

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

  • Move OptimalStrategyHeadline from routes/strategy/components/ into $lib/components/ (it's now shared) and add an optional showInfoTip prop. The strategy page keeps the tooltip (default true); the calculator variant passes false, which hides the tooltip and appends a short default-assumptions note.
  • New recommended-filing-card.ts — pure, unit-tested logic: optimal-result computation (reusing expectedNPVSingle / expectedNPVCoupleOptimized), mortality-distribution loading, and a shared buildStrategyUrl.
  • New 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.
  • Refactor StrategyPromo.svelte to render the card and reuse the shared buildStrategyUrl (removing its private duplicate). The calculator page itself is unchanged (the card lives inside StrategyPromo).

Notes

  • Privacy preserved: all computation is client-side; nothing is logged or persisted.
  • Single vs. couple copy/layout is handled by the shared OptimalStrategyHeadline.

Test plan

  • npm run test — all 2056 tests pass, incl. 13 new tests for the logic module (compute equivalence to expectedNPV*, exact pre-filled URL strings, mortality-load behavior).
  • npm run quality — Biome + svelte-check clean.
  • npm run build — all routes prerender.
  • Manual: verified the card renders for both single and couple (pre-filled via URL hash), links to the matching pre-filled /strategy, and updates when earnings/PIA change.

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.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 21, 2026

Copy link
Copy Markdown

Deploying social-security-tools with  Cloudflare Pages  Cloudflare Pages

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

View logs

Gregable added 2 commits June 21, 2026 16:01
- 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.
@Gregable Gregable merged commit 354d918 into main Jun 22, 2026
6 checks passed
@Gregable Gregable deleted the worktree-recommended-filing-card branch June 22, 2026 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant