diff --git a/changelog.d/lower-pension-split-threshold.fixed.md b/changelog.d/lower-pension-split-threshold.fixed.md new file mode 100644 index 0000000..20b75ae --- /dev/null +++ b/changelog.d/lower-pension-split-threshold.fixed.md @@ -0,0 +1 @@ +Lower the pension/SS age-aware split threshold from 60 to 55 to match Colorado's 55+ pension subtraction (so mixed-age couples ages 55-59 each claim the state per-person exclusion). Higher-threshold states (DE 60, GA 62, MD 65) are unaffected. diff --git a/policyengine_taxsim/runners/policyengine_runner.py b/policyengine_taxsim/runners/policyengine_runner.py index 9c9bbc8..c0c8d7a 100644 --- a/policyengine_taxsim/runners/policyengine_runner.py +++ b/policyengine_taxsim/runners/policyengine_runner.py @@ -195,16 +195,19 @@ def _initialize_dataset_structure(self) -> dict: } ) - # Pension and Social Security income are split only when both spouses - # meet the state-level age threshold (60, the lowest common threshold - # across states such as DE). In mixed-age households (e.g. spouse under - # 60 while filer is elderly), the income stays with the primary filer so - # age-based state exclusions aren't lost on the younger spouse's - # incorrectly-allocated share. + # Pension and Social Security income are split between spouses only + # when both meet the state-level age threshold (55, the lowest common + # threshold across states such as CO whose pension subtraction + # qualifies filers 55+). In mixed-age households the income stays + # with the older spouse so age-based state exclusions aren't lost on + # the younger spouse's incorrectly-allocated share. Higher-threshold + # states (DE 60, GA 62, MD 65) are unaffected: 55-59 splits don't + # create false exclusions because the filers fail those states' age + # gates anyway. _AGE_GATED_FIELDS = frozenset( {"taxable_private_pension_income", "social_security_retirement"} ) - _AGE_GATED_SPLIT_AGE = 60 + _AGE_GATED_SPLIT_AGE = 55 @staticmethod def _make_primary_split(source_field): diff --git a/tests/test_spouse_income_splitting.py b/tests/test_spouse_income_splitting.py index 4789641..ba50488 100644 --- a/tests/test_spouse_income_splitting.py +++ b/tests/test_spouse_income_splitting.py @@ -107,6 +107,18 @@ def test_pension_splits_when_both_spouses_are_60_plus(): np.testing.assert_allclose(values, [20000.0, 20000.0]) +def test_pension_splits_when_both_spouses_are_55_plus(): + """Pension: when both spouses ≥ 55 (CO's threshold), allocate 50/50 + so each spouse claims the per-person CO pension subtraction. See + taxsim issue #933: CO joint, page=58, sage=56 — both qualify for + CO's 55-64 $20K subtraction. Pre-fix PE put pension on primary + only, giving $20K total subtraction; correct behavior splits 50/50 + so each spouse claims $20K = $40K total (matching TaxAct).""" + df = pd.DataFrame([_base_mfj_record(page=58, sage=56, pensions=40000)]) + values = _run_allocation(df, "taxable_private_pension_income") + np.testing.assert_allclose(values, [20000.0, 20000.0]) + + def test_pension_goes_to_primary_when_primary_is_older(): """Pension: mixed-age, primary older — keep full pension on primary so they claim the per-person elderly exclusion. Splitting 50/50 would