Repository navigation
Conversation
# Conflicts: # policyengine_us/tests/code_health/test_rest_python_groups.py
Run the unchanged input checks in a dedicated Rest group and preserve three isolated processes, distinct reports, and failure propagation. Avoid the differential parent's redundant country import and allow slower probes within a bounded hang guard.
Main's #10401 (ee6c1c5) added the ss-calculator-engine and ss-calculator-differential Rest groups beside this branch's social-security-inputs group. The Makefile keeps all three groups, their file lists and recipes, and lists all three files in REST_LISTED_TESTS so the core and remaining groups don't run them twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Retain E3 changes in ten overlapping files; upstream versions match the original stacked base. Remove the released benefit-lever changelog fragment.
MaxGhenis
marked this pull request as ready for review
October 29, 2026 11:33
This branch has not been deployed
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.
Both prerequisites, #10400 and #10401, are merged. This branch was stacked on their fetched heads.
Adds an opt-in COLA means test shared by reported Social Security benefits and the supplied-record household calculator. Implements design v3 E3 as replaced by M6, the A5.1 timing/high-water rules and A5.2 joint numerator, A1's calculated-source composition, and P2's static-cross-section convention. Defaults retain current law.
Stack and merge history
The branch was built from then-main
d92649c6dab5f49f788441cd60179a578d549ab9, which included #10401 head04c2b04848e93abff41c113b11433358924cd86c, and merged #10400 heada6dcc92217ae60127edd588295684f332713ff1awhile that PR was open. That original stack merge needed no manual conflict resolution; identical shared files remain once.After both prerequisites merged, this branch merged main
4c65c821919d3db651eb79603225491a04b7a087, retaining its history. Ten overlapping files retained the E3 versions: the benefit-lever guide and helper, four public benefit variables and four withholding variables. The incoming versions were verified byte-identical to original stack basea498bb4da70b657c7770bbc967ab5432ae777a30. The released A5 changelog fragment was removed. No prerequisite merge remains outstanding. The continuation started at481091a5dcbb8737b771ece7adddb6c0c26e39b8and fetched upstream main8b17892d2cba99a82961ea32fbaf9d69c6ba73d6. A final fetch reached main1976c4b60076cd2d133faf12f61b242d9ca67020; it changes none of E3's paths and a trial merge is clean, so no further main merge or conflict resolution was needed. Continuation commit4f336b78e2cc687b46f83d16e0067d7108df82ebaligns the legacy calculated-base fixture with A1's complete payment amount. Commit2c142b89d48ead3c29786a150b0ec570e1d65e08restores the disabled-E3 legacy COLA path and updates the affected synthetic/source-validation fixtures.Policy mechanics and choices
OACT A9, 2026 Trustees Report basis, retrieved live during implementation: “Use prior tax year income data for this determination.” A9 withholds COLAs above CPI-U-indexed lines, pays chained CPI-U below them, and uses chained CPI before receipt. The dedicated annual TaxUnit variable
social_security_cola_means_test_magiexcludes taxable Social Security and retains applicable deductions and IRMAA addbacks, following the linked memorandum, provision 5 and H.R. 6489 section 103(d). January payment yearyreads income and filing status from tax yeary−1.The configurable lever differs from A9 in two intended ways: below-line COLAs default to statutory, and scope defaults to first-eligible cohorts from 2026. Chained CPI-U and all beneficiaries are selectable. A separate pre-receipt index defaults to following the below-line choice; pre-receipt events use that index without an income test. The
a9preset selects all beneficiaries from the December 2028 COLA, chained CPI-U below the line and before receipt, and $85,000/$170,000 thresholds in 2018 dollars indexed by CPI-U. The first affected checks are January 2029. Its indexed dollar amounts use PE-US's CPI-U path; the preset reproduces the provision's mechanics rather than OACT's projected dollar estimates or solvency results.The policy defaults off. Effective year/month, cohort start, filing groups, threshold lines, dollar base year, CPI-U lag and rounding are parameters. An active A5 alternative-rate path overrides the selected index; the applicable percentage-point change is then added with a zero floor. Withholding overrides the entire resulting increase.
means_test.enabledactivates the income decision and selected index without a second switch. When E3 is disabled,cola.withholding_enabledretains A5's externally resolved withholding channel. Explicit component decisions andss_calculator_withhold_colaretain override precedence. Automatic decisions retain timing, cohort and receipt restrictions; manual component inputs retain their prior carry-forward behavior when the automatic policy is inactive, while calculator-specific decisions apply only in their supplied year.Divergences and documented conventions
scopeuses0=first_eligible_cohorts,1=all_beneficiaries; the below-line index uses0=statutory,1=chained_cpi_u; the pre-receipt index adds-1=follow_below_threshold.income_sensitivityuses0=prior_year,1=never_withheld,2=always_withheld. Filing-group mappings use0=single,1=joint. The semantic choices are unchanged.Shared decisions, invariants and tests
Each exposed event uses one joint numerator:
1if withheld, otherwise1 + adjusted_COLA, divided by1 + statutory_COLA. Withholding does not reset the index high-water base or create a later catch-up increase. Neither withholding nor a downward adjustment reduces the nominal benefit level. Switching the policy off later preserves earlier effects.The calculator resolves receipt by the first check month and applies these same decisions inside its COLA schedule. Payment outputs avoid unnecessary next-January income reads. Calculated public routes bypass population factors already applied by the calculator's ledger; reported routes retain the stable multiplication order. Across-the-board and payable factors also apply once, before the calculator's earnings test.
The following tests are in
policyengine_us/tests/unit/test_ss_cola_means_test.py:test_neutral_defaults_require_explicit_threshold_package;test_property_means_test_off_preserves_stacked_base_outputs;test_means_test_off_preserves_downstream_dependency_closuretest_each_index_scope_combination_and_first_eligible_boundarytest_static_cohort_proxy_is_reconstructed_within_each_score_yeartest_equality_is_paid_and_each_filing_status_has_an_explicit_group;test_surviving_spouse_mapping_is_a_parametertest_only_prior_tax_year_income_and_filing_status_make_the_decision;test_magi_excludes_social_security_and_retains_irmaa_addbackstest_supplied_income_history_overrides_the_extended_record_proxy;test_static_cross_section_proxy_sensitivitiestest_cpi_u_threshold_indexing_and_decimal_half_up;test_chained_index_uses_q3_high_water_and_half_up;test_chained_index_reads_all_three_q3_months;test_zero_cola_and_downward_adjustment_floortest_two_year_cpi_e_and_withholding_use_one_joint_numerator;test_property_joint_factor_equals_product_of_per_year_ratiostest_calculated_source_applies_withholding_and_cpi_e_oncetest_pre_receipt_index_is_separate_and_has_no_income_withholding;test_midyear_first_check_retains_the_pre_receipt_index;test_named_withholding_uses_selected_calculator_cohort_and_receipttest_explicit_withholding_input_remains_a_final_decision;test_disabled_means_test_preserves_manual_input_carry_over;test_disabled_later_policy_retains_an_earlier_withheld_eventtest_a9_preset_reproduces_captured_descriptiontest_multi_year_income_dependency_graph_is_acyclictest_property_a_withheld_year_never_raises_the_benefit;test_property_withholding_is_monotone_in_incomeThe new YAML case,
policyengine_us/tests/policy/contrib/ssa/benefit_levers/social_security_cola_means_test.yaml, covers prior-year income, equality, an excluded older cohort and the CPI-E/withholding numerator through the policy test runner. The separate disabled-policy differential against archived main4c65c821919d3db651eb79603225491a04b7a087matched five legacy public-input reported situations, five calculator situations, five pure published examples and all 149,182 cached entries exactly.Unmodeled cases and sensitivity flags
Population scoring uses the static-cross-section prior-income proxy: the same record's dataset-extended
y−1copy, not an observed longitudinal income history. Supplied complete histories override it. Useincome_sensitivity=1and2for the never-withheld and always-withheld envelope; these retain automatic timing, cohort and receipt restrictions. The engine does not carry a person's income, cohort or composition across projected rows.Missing entitlement and worker information retains A5's declared exposure proxies. Identified records can supply component
_worker_eligibility_year,_worker_id,_entitlement_year/monthand_first_cola_year/month. Integer-age uncertainty calls for adjacent-cohort sensitivities; disability/young-auxiliary pre-start exposure calls for supplied current-year entitlement or first-COLA alternatives. These assumptions are not observed histories. Auxiliary PIA inversion without worker/share information remains unidentified.The supplied-record calculator retains its existing scope: own retirement and restricted survivors. Disability, spouse, child, minimum and dual-entitlement computations are outside that route. Its scope assertions include
ss_calculator_no_special_monthly_test,ss_calculator_no_prior_withholding_adjustment,ss_calculator_earnings_test_no_trigger, explicit prior-disability information and an authoritative basis when required, plus ordinary non-WINDEX and nonbinding survivor-limit assertions. Unsupported historical computation/rounding routes fail; chained CPI-U rates require payment year 2002 or later. See the calculator guide and benefit-lever guide.No population impact or OACT solvency result is inferred from these mechanics. Population scoring requires the hub's pinned artifact, policy settings and sensitivity receipt.
Overlap with #10484
Rechecked #10486 at
2c142b89d48ead3c29786a150b0ec570e1d65e08and #10484 (ss-pia-ratio-lever-c) atfea0d26ef98a6771e946f621e8edd2bff11a046c, with shared merge base4c65c821919d3db651eb79603225491a04b7a087. The intersection of changed files is empty, both from the actual fork-base comparisons and the PR diffs. A trial merge is clean.The policies interact semantically: #10484 supplies the eligibility-year PIA ratio; E3 supplies COLA index/withholding decisions. Reported routes compose their respective population factors, while calculated routes already apply applicable PIA/COLA changes inside the calculator and bypass those population factors. Combined runtime validation of both PRs together has not been run. #10484 was not changed.
Validation
Initial required local validation passed at
481091a5dcbb8737b771ece7adddb6c0c26e39b8. CI then exposed the two compatibility issues described below. The new Python file was rerun after the model fix; the completed counts and final-head CI results are recorded here:ruff format --check .;ruff check .passed, using the locked Ruff 0.15.5.env -u UV_FROZEN uv lock --checkpassed without relocking; whitespace checks passed. Nothing under.github/was changed.policyengine_us/tests/unit/test_ss_cola_means_test.py: 42 passed in 779.06 seconds, in one clean full-file run, exit 0; no split was needed.481091a5dcbb8737b771ece7adddb6c0c26e39b8; retained rather than repeated.social_security/ss_calculated_benefit.yaml: all 8 cases covered. Prepared splits 1–3: 3 passed in 25.64 seconds (413.55 seconds command wall time); 4–6: 3 passed in 22.28 seconds (355.92 seconds wall time). Cases 7–8: 2 passed in 135.49 seconds, exit 0, from the prior build at initial head481091a5dcbb8737b771ece7adddb6c0c26e39b8. Splitting retains the prior full-file 4 GB limit finding; no cap was raised.The first ready CI run exposed one legacy fixture in
policyengine_us/tests/policy/contrib/ssa/benefit_levers/social_security_retirement.yaml(9 passed, 1 failed). Its reserved-route comment and $8,800 expectation predated the implemented calculator ledger. A1 requires across-the-board and payable changes once, before the earnings test. The injected $10,000 base now represents complete calculated checks: the public route must return10000 * 1 = 10000; the old10000 * 1.1 * 0.8 = 8800repeated those changes. The first continuation commit corrects that expectation and its explanation, preserving the calculator ledger and its independently passing composition test. This file is outside the allowed local regression scope; its full 10-case rerun passed in final-head CI.The next run exposed three legacy-helper failures in
policyengine_us/tests/core/test_social_security_lever_properties.pyand four outdated exception assertions inpolicyengine_us/tests/core/test_social_security_inputs.py. The model now avoids E3 calculator/history inputs when the means test has never been enabled, and uses the original annual manual-withholding channel for disabled E3 events. This preserves the original hand calculations: historical COLA1.1135 / 1.112, persistent withheld COLA1 / 1.036, and mixed reported/calculated factors[1.0375 / 1.036, 1]. The synthetic parameter fixture gains only the neutralmeans_test.enabled=falseleaf. Source-validation tests still reject every unmatched source/calculator pair, expecting the implemented route'sValueErrorrather than the old reserved-route exception. No numerical expectation in either core file changed. Both full files were delegated to CI under the local scope restriction.make format, Ruff andenv -u UV_FROZEN uv lock --checkpassed before each continuation commit, without relocking.Paths in the following tables are relative to
policyengine_us/tests/policy/baseline/gov/ssa/:social_security/social_security_retirement.yamlssi/income/ssi_unearned_income.yamlssi/ssi_countable_income.yamlssi/eligibility/income/deemed/from_ineligible_parent.yamlssi/eligibility/income/deemed/from_ineligible_spouse.yamlssi/integration_tests.yamlNo existing baseline SSA YAML activates the new means-test parameters, which default disabled; the new Python/YAML cases test those decisions and MAGI. The calculator splits cover the changed engine. Upstream AIME/PIA/FRA and earnings-history files, revenue cases that generally supply aggregate benefits, and farther SSI resource/arrangement consumers were validated by CI. This follows the assigned focused local scope and avoids repeating the long folder run under the lane's I/O clamp. The local prohibition leaves
revenue/test_tob_revenue.pyto CI. No file outside the required new Python file and the selected SSA regressions was run locally; no microsimulation was run.The remaining 48 files are listed below: 47 YAML files / 346 enumerated cases, routed through the existing
Full Suite - Baseline (ssa-usda)job, and the TOB Python file through the existing Restpolicygroup. The E3 Python file remains in the existing Restremaininggroup. No CI routing was added.revenue/employer_medicare_tax_income_tax_revenue.yamlrevenue/employer_ss_tax_income_tax_revenue.yamlrevenue/tax_unit_taxable_social_security_pre_1993.yamlrevenue/test_tob_revenue.pyrevenue/tob_revenue_medicare_hi.yamlrevenue/tob_revenue_oasdi.yamlrevenue/tob_revenue_total.yamlrevenue/tob_tier_split.yamlsocial_security/integration.yamlsocial_security/multiyear_integration.yamlsocial_security/ss_aime.yamlsocial_security/ss_aime_input.yamlsocial_security/ss_claiming_age.yamlsocial_security/ss_covered_earnings_this_year.yamlsocial_security/ss_earnings_test_reduction.yamlsocial_security/ss_full_retirement_age_months.yamlsocial_security/ss_pia.yamlsocial_security/ss_quarters_of_coverage.yamlsocial_security/ss_retirement_age_adjustment_factor.yamlss/never_eligible_for_social_security_benefits.yamlssi/eligibility/income/deemed/from_ineligible_spouse/ssi_income_deemed_from_ineligible_spouse.yamlssi/eligibility/income/deemed/ssi_income_deemed_from_ineligible_spouse.yamlssi/eligibility/income/deemed/ssi_ineligible_child_allocation.yamlssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yamlssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.yamlssi/eligibility/income/ssi_blind_or_disabled_working_student_exclusion.yamlssi/eligibility/resources/deemed/is_ssi_spousal_resource_deeming_applies.yamlssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_parent.yamlssi/eligibility/resources/deemed/ssi_resources_deemed_from_ineligible_spouse.yamlssi/eligibility/resources/meets_ssi_resource_test.yamlssi/eligibility/ssi_marital_both_eligible.yamlssi/eligibility/status/ssi_federal_living_arrangement.yamlssi/income/ssi_earned_income.yamlssi/income/ssi_engaged_in_sga.yamlssi/income/ssi_marital_earned_income.yamlssi/income/ssi_marital_unearned_income.yamlssi/is_ssi_aged_blind_disabled.yamlssi/is_ssi_disabled.yamlssi/is_ssi_eligible.yamlssi/is_ssi_qualified_noncitizen.yamlssi/meets_ssi_disability_criteria.yamlssi/ssi.yamlssi/ssi_amount_if_eligible.yamlssi/ssi_claim_is_joint.yamlssi/ssi_couple_computation_applies.yamlssi/ssi_if_takes_up.yamlssi/ssi_living_arrangement_integration.yamlssi/uncapped_ssi.yamlAt final head
2c142b89d48ead3c29786a150b0ec570e1d65e08, SSA/USDA CI passed all 54 SSA YAML files / 389 cases. All 48 delegated files passed: 47 YAML files / 346 cases plus both TOB Python cases (183.756 case-seconds). The six Rest Python shards all passed; their JUnit reports confirm 42 E3 cases (244.005 case-seconds), 126 source-validation cases (290.014 case-seconds), and 24 lever-property cases (0.988 case-seconds), all passing. These CI case-time sums exclude collection and process overhead. Quick Feedback also passed: the new YAML case passed in 18.43 seconds, the corrected retirement YAML passed all 10 cases in 96.09 seconds, and the E3 Python file passed a clean 42-case full-file run in 233.22 seconds. The microsimulation suite and all Contrib shards passed. The complete CI run concluded success at this head: 34 checks passed and 1 was skipped, with no failures. The final-head watch completed within the requested 100-minute limit, with polls at least five minutes apart.At the final head, the clean full-file attempt reached the unchanged 4 GB RSS cap after 761.9 seconds, with 40 passing results printed and no assertion failure. The allowed
-ksplit separates the 40 earlier cases from the two downstream dependency-closure cases.-k 'not means_test_off_preserves_downstream_dependency_closure': 40 passed in 277.78 seconds, exit 0.-k 'means_test_off_preserves_downstream_dependency_closure': 2 passed in 59.66 seconds, exit 0.Local country-importing processes used the supplied Python 3.13.9 environment and locked Core 3.33.2, serially, only starting while load1 was at or below 100. Each process retained 4 GB RSS, 1,800 seconds and four numeric threads. No local test environment was created. The earlier exact current-law disabled-policy differential is retained; the compatibility fix leaves its neutral current-law path unchanged.
impact: none under current law (contributed reform); the hub will measure
axiom: n/a: contributed reform, not enacted law