Calculation catalog › Cash flow and summary

Projection summary coast fire number

Current invested amount needed to reach the FI target without further contributions.

Field: coastFireNumber Unit: US dollars Basis: today's dollars (real) Computed by: Engine Status: Complete chain

Appears in: results-headline (Coast FI number); report (headline-results block coast-fire-number and ReportPage KPI); mcp (run_projection.summary.coastFireNumber); mcp (compare_scenarios.a.coastFireNumber); mcp (compare_scenarios.b.coastFireNumber)

Calculation records

  • Projection summary coast fire number Composition record, justified by derivation

    Purpose: Discount the FI number to today at the simple real return over the whole-age horizon.

    Statement: projection/compare.ts#summarizeProjection publishes the start-year amount that reaches the upstream FI number at retirement with no further contributions by discounting it over the whole years to the household's later retirement, max(0, retirementYear - startYear) (projection-summary-fi-spending-base), at the simple real return defaultReturnPct/100 - inflationPct/100; for one person that is retirementAge - (startYear - birthYear).

    Formula: coastFireNumber = fiNumber / (1 + defaultReturnPct/100 - inflationPct/100)^max(0, retirementYear - startYear)

    • fiNumber: Upstream FI number (unit: start-year USD) (domain: finite)
    • n: Whole-age horizon to retirement (unit: years) (domain: integer >= 0)
    • realReturn: Simple real return, general inflation only (unit: 1/year) (domain: finite)

    Timing: projection start year, discrete annual compounding

    Rounding: none; no floor on the discounted amount

    Limits:

    • The real return is the subtraction of the two rates, not the Fisher ratio, and the horizon is retirement age rather than the FI-number spending year; a person already at or past retirement has a zero horizon, so Coast FIRE equals the FI number. Healthcare extra inflation, continuous compounding, intermediate rounding and a final floor are all outside the contract. An empty ledger adds no fallback beyond whatever the FI number already published.

    Provenance: derived by codex, implemented by claude.

    Independent review: cursor

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: projection-summary-coast-fire-number.md Mutation receipt: projection-summary-coast-fire-number.mutation.md

    Evidence tests: compareSummary.evidence.test.ts

    Implemented in: compare.ts

    Is the number of: projection-summary-coast-fire-number

Records that feed this number

  • The household's later retirement, one rule for FI and the funded ratio Model record, justified by derivation

    Purpose: The year the household stops earning, whose it is and which rule gave it, never whoever is listed first.

    Statement: projection/householdRetirement.ts#personRetirement gives each person's retirement year, the first year without their work, and its rule. A wage stream of theirs with gross pay above 0 pays through birthYear + stopAge - 1, stopAge being its end age, else the retirement age (stopAge = endAge ?? retirementAge, as projection/internal/wageIncomeStreams.ts pays), and with neither through their last year alive at the planning age, never after it. With a retirement age the person retires in the later of the ISO birth year plus that age (retirementAge) and the year after their last wage year, when a stream's end age keeps paying past the retirement age (wagesPastRetirementAge); with none, in the year after their last wage year when that year is the start year or later (wagesEnd), otherwise in the start year (startYear). A person retires in the plan only when alive in max(year, startYear): one whose wages run through their last year alive works through the plan, a retirement age past the planning age is never reached, and a planning age ended before the start retires no one. projection/householdRetirement.ts#householdRetirement leaves those people out (notRetiring) and takes the latest of the rest, a tie going to the older person and then the smaller id by ordinal comparison, so list order never decides it; with nobody retiring in the plan there is no household retirement, and no FI figure, Coast-FIRE figure or funded ratio is priced (decision D-PEOPLE-ORDER; the independent review's M4 and N3). The FI figures (projection/compare.ts#summarizeProjection) and the funded ratio (ladder/fundedRatio.ts#fundedRatioStart) both read it, and projection/householdRetirement.ts#householdRetirementClause and #notRetiringClause word it for every page: they name the person, say which rule applied, and name anyone who works through the plan. Sam, born 1964 with no retirement age, planning age 95 and wages with no end age, works through the plan, so with Alex, born 1962 retiring at 66, the household retires in Alex's 2028; Gus, born 1966 with a retirement age of 65 and wages to age 75, is paid through 2040 and retires in 2041 (round-one review of #765). Units: calendar year. Rounding: none.

    Formula: year(p) = retirementAge !== null ? (lastWage(p) !== null ? max(birthYear + retirementAge, lastWage(p) + 1) : birthYear + retirementAge) : lastWage(p) !== null and lastWage(p) >= startYear ? lastWage(p) + 1 : startYear, lastWage(p) = max over p's paying wage streams of min(stopAge !== null ? birthYear + stopAge - 1 : birthYear + planningAge, birthYear + planningAge) with stopAge = endAge ?? retirementAge, and null when p has no paying wage stream; in(p) = max(year(p), startYear) <= birthYear + planningAge; household = argmax year over the people with in(p), ties to the earlier dob then the smaller id, none when nobody has in(p)

    • year(p): A person's retirement year, the first year without their work (unit: calendar year) (domain: integer)
    • lastWage(p): The last year one of their wage streams pays, null when none pays (unit: calendar year) (domain: integer or null)
    • in(p): Whether the person is alive in the year their retirement would be priced (unit: boolean) (domain: true or false)

    Timing: once per reading, from the plan (not a Monte Carlo path's sampled deaths)

    Rounding: none

    Limits:

    • A convention, not a statute: a retirement age is the first year without wages unless a wage stream's end age runs past it, and then the wages decide; a person who never stops earning is said to work through the plan, not given a year
    • A person who retires after the other person's planning age has ended still sets the household's retirement: the priced year is one they are alive in, whether or not their partner is
    • Wages are the plan's only earned income; the rule reads the plan's wage streams and planning ages, not a Monte Carlo path's sampled death

    Provenance: derived by claude, implemented by claude.

    Independent review: codex

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: household-later-retirement.md Mutation receipt: household-later-retirement.mutation.md

    Evidence tests: householdRetirement.evidence.test.ts

    Implemented in: householdRetirement.ts

    Feeds: projection-summary-fi-number, projection-summary-fi-age, projection-summary-coast-fire-number, projection-summary-fi-year, projection-summary-average-pre-retirement-savings-rate-pct, funded-ratio-result-essential-spending-pv, funded-ratio-result-guaranteed-income-pv, funded-ratio-result-funded-ratio-pct, funded-ratio-result-unfunded-pv

  • Projection summary fi number Composition record, justified by derivation

    Purpose: Price one selected year of gross outflows against the safe-withdrawal-rate lens.

    Statement: projection/compare.ts#summarizeProjection publishes the FI number in projection-start-year dollars as one selected year's nominal funded expenses plus tax and penalties, discretely deflated by general inflation, divided by the safe-withdrawal-rate decimal; an empty ledger instead divides base annual lifestyle spending alone by that rate. The year is the household's later retirement, and when the plan converts to Roth in any year that year's figures come from the plan run without its conversions (projection-summary-fi-spending-base).

    Formula: fiNumber = ((expenses.total + tax + penalties) / (1 + inflationPct/100)^(spendingYear - startYear)) / (safeWithdrawalRatePct / 100); empty ledger: baseAnnual / (safeWithdrawalRatePct / 100)

    • spendingYear: max(startYear, the household's later retirement year), else the first ledger year (unit: calendar year) (domain: integer)
    • expenses.total: Published funded spending after guardrails (unit: nominal USD) (domain: nonnegative)
    • safeWithdrawalRatePct: Safe-withdrawal-rate lens, default 4 (unit: percent/year) (domain: positive)

    Timing: one selected calendar year, deflated to the projection start year

    Rounding: none; no intermediate rounding or floor

    Limits:

    • Gross outflows, not net portfolio need: guaranteed income is not subtracted, and published funded expenses.total is used rather than intended spending, so guardrail cuts are already in the base. Deflation is discrete annual general inflation, never the healthcare extra rate. The empty-ledger path is base lifestyle only, with no tax, penalties or deflation, and a horizon that ends before retirement prices the first ledger row rather than interpolating a retirement-year spend. The rate is a lens; the ledger does not spend at it.

    Provenance: derived by codex, implemented by claude.

    Independent review: cursor

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: projection-summary-fi-number.md Mutation receipt: projection-summary-fi-number.mutation.md

    Evidence tests: compareSummary.evidence.test.ts

    Implemented in: compare.ts

    Is the number of: projection-summary-fi-number

    Feeds: projection-summary-fi-age, projection-summary-coast-fire-number, display-fi-target-annual

  • Which year and which outflows the FI figures price Composition record, justified by derivation

    Purpose: The household's later retirement year, and that year's outflows without a Roth conversion's one-off tax.

    Statement: projection/compare.ts#summarizeProjection prices the FI figures on the calendar year max(startYear, retirementYear), where retirementYear is the household's later retirement (household-later-retirement: a retirement age gives birth year plus that age, or the first year without the person's wages when a wage stream's end age keeps paying past it; a person with none retires in the first year without their wages, else in the start year; a person who never retires in the plan is left out and named in fiBasis.notRetiring; a tie goes to the older person, then the smaller id; decision D-PEOPLE-ORDER, rule R4), so list order never decides it; fiBasis.personId names that person, fiAge is their age, and fiBasis.retirementRule says which rule gave the year. When nobody retires in the plan, no FI figure is priced: fiNumber, fiYear, fiAge and coastFireNumber are null and fiBasis.spendingSource is noRetirementInPlan (the independent review's N3). The priced outflows are that year's published expenses.total + tax + penalties, except when the plan converts to Roth in any year (rothConversion > 0 or a named conversion request in some year): then they are the same year's figures from the plan run with its Roth conversions removed, so neither a conversion's one-off tax nor the costs it causes later (the IRMAA lookback, a drained taxable account) is priced as spending and converting more can never lower the figure (withoutRothConversions: the strategy set to none, named and legacy-aggregate conversion requests and the withdrawals they name as tax funding dropped), which the caller supplies as SummarizeProjectionOptions.conversionFreeRun and which runs at most once (decision D-FI-CONVERSION-TAX). fiBasis.spendingSource publishes projection, conversionFreeProjection, conversionTaxIncluded (the plan converts and no conversion-free run was supplied), baseAnnual (an empty ledger) or noRetirementInPlan. Pat (1980, retiring at 50) and Robin (1983, retiring at 49) price 2032, Robin's; with 80,000 of 2032 expenses, 30,000 of tax on a 100,000 conversion and 8,000 of tax without it, the FI number at 3 percent inflation and a 4 percent rate is 88,000 / 1.03^6 / 0.04 = 1,842,465.36, not 2,303,081.71. Units: calendar year; start-year USD. Rounding: none.

    Formula: retirementYear = householdRetirement(plan, startYear).retirement.year (no FI figure when null); y = max(startYear, retirementYear); base = (the conversion-free run's row y if any row converts, else row y): expenses.total + tax + penalties

    • retirementYear: The household's later retirement year (unit: calendar year) (domain: integer)
    • y: The priced year, else the first ledger row when absent (unit: calendar year) (domain: integer)
    • base: That year's outflows without a conversion's tax (unit: nominal USD) (domain: nonnegative)

    Timing: once per summary; the conversion-free run only when the plan converts

    Rounding: none

    Limits:

    • The conversion-free run is a whole projection without conversions, so the priced year also differs by what earlier years' conversions did to the balances and withdrawals, not only by that year's conversion tax; it is the year the household would have had had it never converted
    • The conversion-free choice is a required argument (the independent review's M3): the planner's projection, compareRothConversion and compareScenarios pass the run; Monte Carlo paths, the optimizer and decision candidates, the SWR, relocation, care, survivor and Social Security comparisons, the scenario plan comparison and the app's case runners pass null and show no FI figure, and a converting plan then publishes conversionTaxIncluded. RetireGolden-MCP chose in 0.11.0, and 0.12.0 keeps it: the summaries it publishes, run_projection's summary and compare_scenarios' a and b, pass the run, so their FI figures are the app's; batch_evaluate and solve_max_spending pass null for the summaries they only read (lifetime tax, ending balances, the after-tax estate), and no such summary reaches a response whole
    • The later retirement is a household convention, the year the last earner stops; the program states it and the page names the person

    Provenance: derived by claude, implemented by claude.

    Independent review: codex

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: projection-summary-fi-spending-base.md Mutation receipt: projection-summary-fi-spending-base.mutation.md

    Evidence tests: compareSummary.evidence.test.ts

    Implemented in: compare.ts; householdRetirement.ts

    Feeds: projection-summary-fi-number, projection-summary-fi-age, projection-summary-coast-fire-number, projection-summary-fi-year, projection-summary-average-pre-retirement-savings-rate-pct

Engine source: engine/src/projection/compare.ts (ProjectionSummary.coastFireNumber)

The evidence links on this page (each record's worksheet, mutation receipt, evidence tests and implementation, and the source links) are pinned to engine commit 2624dbdba9fd, committed 2026-10-11. The live calculation index and output-family census links point at the repository's main branch, so you can check this snapshot against them.