How we model federal retirement benefits.
Every formula on /plan/federal is wired to its primary source — Title 5 USC, Public Law 118-273 (Social Security Fairness Act), OPM CSRS-FERS Handbook, SSA fact sheets, and POMS. The page below is the public audit of how each number is computed.
Social Security Primary Insurance Amount (PIA)
PIA is the monthly benefit a worker would receive if they file at their Full Retirement Age. It comes from a three-tier formula on the worker's Average Indexed Monthly Earnings (AIME):
Bend points B1 and B2 are pinned to the worker's eligibility year (the year they turn 62). For 2025 eligibility B1 = $1,226 and B2 = $7,391 monthly. AIME is the average of the worker's top 35 years of earnings, indexed to the year they turn 60 by the SSA National Average Wage Index.
Full Retirement Age and claim-age adjustments
FRA depends on birth year. For workers born 1960 or later, FRA is 67. Earlier birth years get FRA between 65 and 66+10mo. Claiming earlier than FRA reduces the benefit by 5/9 of 1% per month for the first 36 months early, then 5/12 of 1% per month beyond that. Claiming later adds delayed-retirement credits of 8% per year (2/3 of 1% per month) up to age 70.
Windfall Elimination Provision (WEP)
WEP modifies the PIA formula for workers who earned a pension from non-covered employment (CSRS, certain state/local government, foreign) AND are also eligible for Social Security from other covered work. The 90% factor on the first PIA bend point is replaced with a smaller factor that scales by Years of Coverage (YOC) — meaningful Social-Security-covered earnings:
The reduction is also capped two ways: (1) at 50% of the non-covered pension, and (2) at the SSA-published maximum reduction for the worker's eligibility year. For 2025 eligibility, the maximum is $613/mo. Both caps are applied; the smaller controls.
Government Pension Offset (GPO)
GPO reduces a Social Security spousal or survivor benefit by two-thirds of the claimant's own non-covered government pension. The reduction can fully eliminate the spousal/survivor benefit. GPO never reduces a worker's own retirement benefit — that's WEP's territory.
Social Security Fairness Act (SSFA)
Public Law 118-273, signed January 5, 2025, repeals both WEP and GPO for benefits payable January 2024 and after. The model exposes a toggle so users can compare: pre-SSFA the WEP/GPO reductions apply as above; post-SSFA they're zero. The aggregator returns both regimes side-by-side regardless of toggle position so the user can see the exact dollar impact.
For users who started receiving WEP- or GPO-reduced benefits before SSFA's enactment, the model estimates a retroactive lump sum equal to the monthly increase × the months from the later of January 2024 or the user's claim start, through January 2025 (when SSA cut over to paying the higher amount going forward).
FERS basic annuity
FERS basic annuity = high-3 average salary × multiplier × years of service. The multiplier is 1.0% by default, 1.1% for retirees aged 62 or older with 20+ years of service. Special-category employees (LEO, Firefighter, ATC) get 1.7% on the first 20 years and 1.0% beyond. Survivor elections of 25% or 50% reduce the retiree's annuity by 5% or 10% respectively.
FERS Annuity Supplement
For FERS retirees who separate at MRA with 30+ years of service, or at age 60 with 20+ years, the FERS Annuity Supplement bridges from MRA to age 62. The formula is the SSA benefit at age 62 × (creditable civilian service / 40). The supplement is subject to the SSA earnings test — $1 of supplement reduces $2 of earnings above the annual exempt amount ($23,400 in 2025).
CSRS basic annuity
CSRS basic annuity is tiered: 1.5% × high-3 × first 5 years of service, plus 1.75% × high-3 × next 5 years, plus 2.0% × high-3 × all years beyond 10. Capped at 80% of high-3, reached at 41 years 11 months of service.
FEHB and the 5-year rule
To carry FEHB into retirement, an employee must be enrolled in FEHB for the 5 years immediately preceding retirement, or since first eligible. Employees who fail this gate lose the government premium subsidy in retirement. The model surfaces an explicit eligibility verdict so planning does not assume coverage. Multi-year premium projection assumes 6% annual increase (10-year OPM weighted average).
COLA index — CPI-W vs CPI-U
SSA uses CPI-W (Consumer Price Index for Urban Wage Earners) by statute. The model offers an alternative CPI-U projection (the broader BLS index covering all urban consumers). CPI-U typically runs about 0.2 percentage points higher than CPI-W historically because of basket weighting differences. The toggle does not change the legal index — it lets users see the impact of the alternative measure on lifetime real income.
Optimal Social Security claim age
The model scans claim ages 62 through 70 and computes the present value of the lifetime monthly stream from each candidate age, discounted from age 62 (today) at the user's real discount rate, with annual COLA applied. The optimal age maximizes that PV. Sensitivity bars show the optimum at life expectancies of 75, 80, 85, 90, and 95 so users can see how robust the recommendation is. Single-life PV — spousal or survivor strategy can shift the optimum.
lib/plan/federal/optimal-claim.ts.What's NOT modeled (yet)
Honest disclosure: the engine does not yet model the SSA earnings test as it interacts with the FERS Annuity Supplement; long-term care insurance interactions with TSP withdrawal sequencing; survivor benefit timing strategy across both spouses' SS election dates; or the interaction between FERS Annuity Supplement and SSA earnings-test reductions. These are documented follow-ups in the engine's repository README.
Source bundle
Data tables and citations are pinned at the file level. The reference tables for SSA bend points, OASDI wage base, AWI, YOC thresholds, WEP max reductions, FRA ladder, FERS MRA ladder, and IRS RMD divisors all live under lib/plan/federal/data/ with a one-line citation header per file pointing to the source publication and refresh cadence. Update each annually as SSA, OPM, and IRS publish their respective rate notices.
Code review: the engine source is lib/plan/federal/; the Python backend lives in server.py at /api/retirement/social-security-pia, /api/retirement/fers-annuity, and /api/retirement/csrs-annuity. Test coverage is 79 pytest cases on the Python side and 29 vitest cases on the TypeScript side.