Repository navigation
Add annual Social Security earnings histories and per-year reforms - #10560
Conversation
Add explicit complete-history inputs, annual cap/indexing ledger and claim-year freeze, reusing the supplied-record PIA/payment pipeline. Share legacy-compatible indexing and highest-years helpers and add conventional, SSA-example and legacy differential tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Extract one staged per-year kernel shared by reform Variables and history records, preserving intermediate overrides and lazy parameter reads. Add adjusted draw before each ordinary benefit cap and retain tax-room and NIIT-exclusion diagnostics separately. Freeze the pre-extraction arithmetic in differential and property tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Apply the shared eligibility-year formula to annual indexed earnings divided by 12, select the highest 40 mini PIAs and divide by 37. Blend with conventional PIA using a neutral-by-default 2032–2036 parameter path, retaining exact rational intermediates until final dime truncation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep separate fixed-threshold OACT 2025 variants and a configurable neutral custom path. Tax and optionally credit only the covered stream above max(ordinary cap, threshold), index and select its own highest 35 years, and add the eligibility-cohort AIME-plus component after the mini blend. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expose exact annual earnings, E1, donut, indexing and mini-PIA diagnostics through the household report. Preserve complete JSON sources through export, document archived OACT rules and modeling conventions, and isolate new engine/differential files on existing Rest runners. Add future-cohort, source-isolation, reporting and full SSA payment examples. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Break the recursive local-function cycle after each selected-stage or complete annual calculation so Person accessors do not retain entire simulations until cyclic collection. Preserve all arithmetic and lazy dependency behavior; add three GC-disabled weakref regressions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Cohorts first eligible before 1991 have fewer than 35 computation years under 42 U.S.C. 415(b)(2), so a fixed 35/420 understated their AIME (a 1990 witness gave $895 instead of $912). The ordinary history AIME now selects min(35, E - 1956) years and divides by that count times 12; AIME+ and the mini-PIA keep their own rules. The ledger JSON also names the donut credit coefficient and the year that selected it, the January diagnostic PIA's period, and the computation-year count the ordinary flags follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
State the cohort selection rule and its 1990 witness, the combined dime rounding and cohort-selected donut coefficient conventions, Case B's dime floor of SSA's formula result, and that the E2.13/E2.14/B3.12 dates come from the 2025 Trustees Report edition. No parameter value changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: What the item asked and how it's resolved
Hand computations (branch's YAML values: wage base, NAWI, bend points)All cases: $3,000 of covered wages every year from 1951 to E−1, with eligibility and claim in E. The 1951 base ($3,600) is already above $3,000.
Tests (one file per process)
No YAML case was added: the path is a JSON history input plus Python-only tools, and the YAML parameter paths can't express a 1990 career. Mutants (each in its own process; code restored and checked with
|
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Main shipped the public calculator source selectors and the COLA means test. Keep both import sets in engine.py, and take main's selector text in the calculator guide; this branch's "modes remain reserved" text is now false, so only the history-specific guidance survives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6HPC2jULDq8hPQKD71
Main's namespace-classification check fails on any unlisted child of gov.contrib.ssa. Only the household calculator's history route reads this node (history_parameters_at via donut.py and mini_pia.py), so the reference model drops it and the differential can still catch a legacy formula that reads it by accident. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6HPC2jULDq8hPQKD71
|
Ready for hub review Head: Steps
Tests (local, one process per file,
|
|
Ready for hub review This is a round-2 delta review. The PR head hasn't moved past I found no P1 or P2. The r1 P2 is fixed, and the merge with main broke nothing I could find. Two P3s follow. FindingsP3-1. The PR body's CI line still points at the pre-fix head
Replacement for that bullet:
P3-2. Two mentions of E2.13/E2.14 lack the editionThe r1-fix brief asked for the edition wherever the PR names these provisions without it.
Neither changes a result. Replacements: # E2.13's coefficient (2025 Trustees Report edition), selected at
# eligibility 2036; January 2039 formula.The r1 P2: cohort computation yearsHand computation, done before reading the code. I read the raw YAML values on the branch (
At 62 with FRA 65 the factor is 1 − 36 × 5/900 = 0.8, and 498.30 × 0.8 = 398.64 → $398. Production at this head. I ran the pure service with the same parameter files: Through a real The same witness at the r1 head Docs. MutantsI ran each mutant in its own process on a separate worktree, with
All five were killed. TestsI ran each changed test file in its own process with four threads:
That makes 380 passed and none failed. The new cohort tests assert the claim itself, not a weaker one. The 1990 witness asserts the 34- and 35-year sums, AIME, the bends, PIA, the 0.8 factor and the $398 payment. The boundary cases assert n, the sum, AIME (cross-checked against Main merge
Docs:
|
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Brings the branch up to date with main (18 commits behind) before the 1984 benchmark fix round. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
42 U.S.C. 415(a)(4)(B)(i) keeps the December 1978 computation, when larger, for workers with pre-1979 earnings who become eligible before 1984. The history route computes only the wage-indexed 415(a)(1) formula, so it now refuses E = 1983 at computation_years, compute_history, history_pia_details and SuppliedRecord.benchmark (history source only; supplied AIME and PIA keep their 1983 start). The boundary case moves to E = 1984 (28 years, divisor 336), and the docs note that the route assumes no covered wages before 1951, which the 415(a)(4)(B)(ii) subsection (d) guarantee counts. Also names the 2025 Trustees Report edition beside two E2.13/E2.14 mentions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: MergeFast-forwarded to 84eaa12, then merged Finding 1: the supported cohorts start at E = 1984
E = 1984 hand computation, done in a standalone script that reads only the branch's YAML (
Mutant, run in its own process and restored afterwards: setting Finding 2: E2.13/E2.14 edition
Finding 3: PR body
Tests (one file per process)
CIPull request run 41519611528 at 2166886: completed, success, 34/34 jobs (it finished about 70 minutes after the push). Judgment calls
Proposed follow-upSupplied AIME/PIA routes accept E = 1983 although 415(a)(4)(B)(i) can keep the December 1978 computation. The supplied-AIME route computes the 415(a)(1) PIA for E = 1983 through Generated by Claude Code |
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Main moved 59 commits past the branch. Three files changed on both sides and merged without a conflict. owners_draw.py keeps #10571's self_employed_health_insurance_earned_income_limit override in reform.apply. That override reads owners_draw_niit_exclusion, which this branch now computes through the shared kernel, and the kernel takes the same disabled, HI-on and OASDI-only branches as main's formula. The owners' draw docs keep #10571's line 5 section next to this branch's annual-history text. The differential test keeps main's leaf-level classification and adds gov.contrib.ssa.history to NEW_PARAMETER_NODES. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SuppliedRecord.benchmark ran the shared 1983 check before the history route's own 1984 check, so a history record at E = 1982 got "Computation benchmarks before 1983 are unsupported", which implies 1983 works. The history check now runs first, so calculate_year and the engine give the 415(a)(4)(B)(i) reason at E <= 1983, as computation_years, compute_history and history_pia_details already did. Supplied AIME, PIA and survivor records keep the shared 1983 start. The tests now pin both sides of this boundary at the main door: a January 1, 1922 birth attains 62 on December 31, 1983 and is refused, and a January 2 birth benchmarks at 1984, so changing the history check to <= fails. They also check that a supplied PIA, not only a supplied AIME, keeps 1983, and that annual records cannot begin before 1951, the limit the docs rely on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The paragraph on why the history route starts at 1984 said "before 1984" without (B)'s condition that the worker first becomes eligible after 1978, could be read as if (B)(ii) also stopped at 1984, and did not name the subsection. It also left out that 415(d)(2)(A) limits subsection (d) to a worker with a quarter of coverage before 1951, which is what makes the no-pre-1951-wages assumption sufficient. It now also states the route's other assumption: no disability-benefit eligibility before January 1979, the case 415(a)(4)(A) takes outside paragraph (1). Own retirement records have no prior-disability input. The wording follows the delta review's reading of the statute; the build session could not reach a copy of 42 U.S.C. 415 to recheck it. Also rewraps the 100-column donut-coefficient line. Only whitespace changes there, so the rendered page is the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: Three commits on top of
1. Merge with main
Post-merge tests at
All 17 files passed: 617 tests, none failed. 2. Finding 1: the history reason comes first
Nothing relied on the old order:
3. Finding 2: docs paragraph
Statute check: I could not reach any copy of 42 U.S.C. 415.
So every statutory statement in the paragraph is unverified by me:
I applied the paragraph unchanged. Search-engine summaries came back, but they are not fetched text and they contradicted each other. One summary described (a)(4)(A) as pairing January 1979 with old-age eligibility, not disability. Please check (a)(4)(A)'s wording, eligibility against entitlement, against the hub's fetched copy before landing. I read the code behind the paragraph's statements about the route:
4. Finding 3: tests and mutantThe replacement for lines 428-430 is at Traced by hand before running:
Results:
Tests at the head (one file per process)
All 9 files passed: 359 tests, none failed. The head differs from the merge commit only in
CIPull request run 41639987378 at
Judgment calls
Proposed follow-upsAlign the 1984 refusal's stated reason with the docs' (B)(i) scope. State that history records carry no period of disability. Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
US + core hub merge audit, us#10560 at
🤖 Generated with Claude Code |
This PR adds an opt-in annual covered-earnings history source to the household Social Security calculator. A complete supplied career now produces conventional AIME, annual owners' draw credit, the mini-PIA blend, separate above-cap AIME+ credit and a reportable annual ledger, and then enters the existing claiming, COLA, payment-rounding and earnings-test pipeline.
Design
compute_piaservice and household payment pipeline. Equivalent supplied AIME and history-derived AIME consume the same formula path, and applicable payment policies and COLAs run once.min(35, E − 1956)(28 for E=1984, 34 for E=1990, 35 from E=1991);max(ordinary_cap, threshold). AIME+ has its own indexing and top-35/420 calculation for every cohort, and its PIA component follows the mini/conventional blend.ss_calculated_history_*outputs.room_cap_basis, and preserves the existing OASDI-only versus HI-on gross-profit NIIT exclusion.Policy sources
B3.12, OACT 2025 Trustees Report edition: “Sum these individual PIAs for the 40 highest years of indexed earnings and divide that total amount by 37”. That edition raises the retired-worker mini share 20 percentage points per cohort during 2032–2036 and leaves disability benefits alone.
E2.13 and E2.14, OACT 2025 Trustees Report edition: E2.13 reads “Apply OASDI 12.4 percent payroll tax rate on earnings above $400,000”, and E2.14 reads “Apply OASDI 12.4 percent payroll tax rate on earnings above $250,000”. In the 2025 edition both begin with 2027 earnings, hold their thresholds fixed and provide a 2% secondary AIME+ factor for newly taxed above-cap earnings. The 2026 edition moved them to 2028, and this PR keeps the 2025 years and citations.
The conventional calculation follows POMS indexing and cent rounding, base-year rules and AIME/PIA rounding. Tests freeze the complete nominal histories from SSA's published 2027 examples and the corresponding initial PIAs:
Conventions that move results
The annual ledger JSON names these two conventions.
diagnostic_pia_entitlement_monthanddiagnostic_pia_formula_year.donut_credit_rate(withdonut_credit_rate_exact) anddonut_credit_rate_year.Cohort computation years
The ordinary history AIME selects
min(35, E − 1956)years and divides by that count × 12 (42 U.S.C. 415(b)(2): elapsed years from 1951 through the year before age-62 eligibility, less five; POMS RS 00605.016 and RS 00605.017).For example, take a worker born 1928-01-02 who becomes eligible and claims in 1990, with $3,000 of covered wages in 1951–1989. The highest 34 indexed years sum to $372,486.21, which gives AIME floor(/408) = $912, PIA $498.30 and an age-62 payment of $398. A fixed 35/420 would give $375,934.10, $895, $492.80 and $394.
AIME+ and the mini-PIA keep their own selection (35/420 and 40/37). The ledger adds
computation_years, theordinary_top35flags follow it, anddonut_top35still marks 35 years. Legacyss_aimeand the supplied-AIME and supplied-PIA routes give main's results.Other design conventions
supplied_aime,supplied_piaandsupplied_ratio_survivorsources. This PR doesn't addhistoryto that routing: a public source ofhistoryraises the existing source-mismatch error, so callers read history results from thess_calculated_*outputs. The calculator guide says how to place such a check in a public component with a post-constructionset_input.ss_aimekeeps its lookback, age filters and untruncated result. Both paths share applicable indexing and selection arithmetic and have independent differentials where their assumptions match.Decimal(str(...))and then applies annual history cent rounding. The E1 reform keeps its independent $400 draw floor, signed residual and subset conventions, parameter-derived netting and room priority.Interaction with main
Main's COLA means test feeds the calculator engine, and a history record counts as a retirement component there, with the same eligibility, receipt and
ss_calculator_cola_overrideinputs as a supplied-AIME record. For example, take matching history and supplied-AIME records under the means test, in separate tax units, with prior-year MAGI of $150,000 and $50,000 against a $100,000 line, plus a 0 override at $150,000. Both routes give the same January 2027 checks: $256 withheld, $265 paid and $265 overridden. With the means test disabled, all six read $265.test_ss_calculator_differential.pyclassesgov.contrib.ssa.historyas calculator-only, and onlyhistory_parameters_at(viadonut.pyandmini_pia.py) reads it.Tests
test_ss_history_engine.pyruns real Simulation ingress, complete JSON export and reload, future cohort policies, a fixture with all three reforms, and earnings before 1983.test_ss_calculator_differential.pyruns the existing calculator, SSA and downstream outputs with history unselected, including every cached reference intermediate.test_hand_computed_mini_pias_and_fixed_divisor;test_cap_gap_and_threshold_boundaries;test_e1_credit_enters_before_ordinary_cap;test_cap_before_indexing_half_up_cents_and_face_value_from_e_minus_two;test_computation_years_follow_the_elapsed_years_ruleandtest_benchmarks_before1984_rejected_at_each_history_entry_point[1983].308e100b9e(https://github.com/PolicyEngine/policyengine-us/actions/runs/41984891263), concluded success: all 36 jobs passed.impact: none.
ss_calculator_sourcedefaults tooff, the default dataset doesn't hold it, andcalculator_outputskips everyoffrecord, so each new history output reads its default on every record.ss_aimenow calls shared helpers that run main's arithmetic in main's order, and only the owners' draw reform and the calculator read the other new code.axiom: n/a: household calculator and contributed reform paths; current-law results stay the same
🤖 Generated with Claude Code