From 2821f319a91a31c0a6b167f9d19a04d7fe09611a Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 29 Oct 2026 10:08:19 -0400 Subject: [PATCH 1/3] Count railroad retirement annuities as SSI unearned income 42 U.S.C. 1382a(a)(2)(B) and 20 CFR 416.1121(a) count railroad retirement annuities as unearned income, but the SSI unearned income list omitted railroad_benefits, so an aged railroad annuitant received the full federal benefit. Add it to paragraph (a) with statute and POMS SI 00830.225 references, add SSI tests for a reduced and a zero benefit, and update an NH fuel assistance comment that described the gap. Fixes #10533 Co-Authored-By: Claude Opus 5.5 --- .../ssi-railroad-retirement-income.fixed.md | 1 + .../gov/ssa/ssi/income/sources/unearned.yaml | 5 +++ .../ssa/ssi/income/ssi_unearned_income.yaml | 8 +++++ .../policy/baseline/gov/ssa/ssi/ssi.yaml | 33 ++++++++++++++++++- .../nh/doe/fap/nh_fap_countable_income.yaml | 3 +- 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 changelog.d/ssi-railroad-retirement-income.fixed.md diff --git a/changelog.d/ssi-railroad-retirement-income.fixed.md b/changelog.d/ssi-railroad-retirement-income.fixed.md new file mode 100644 index 00000000000..0389133a050 --- /dev/null +++ b/changelog.d/ssi-railroad-retirement-income.fixed.md @@ -0,0 +1 @@ +Count railroad retirement annuities as unearned income for Supplemental Security Income. diff --git a/policyengine_us/parameters/gov/ssa/ssi/income/sources/unearned.yaml b/policyengine_us/parameters/gov/ssa/ssi/income/sources/unearned.yaml index 1d03fba2fd0..a764c21789e 100644 --- a/policyengine_us/parameters/gov/ssa/ssi/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/ssa/ssi/income/sources/unearned.yaml @@ -4,6 +4,7 @@ values: # (a) Annuities, pensions, and other periodic payments. - pension_income - social_security + - railroad_benefits - disability_benefits - veterans_benefits - survivor_benefits @@ -30,3 +31,7 @@ metadata: reference: - title: United States Code of Federal Regulations, Title 20, Subsection 416.1121 href: https://www.law.cornell.edu/cfr/text/20/416.1121 + - title: 42 U.S.C. 1382a(a)(2)(B) + href: https://www.law.cornell.edu/uscode/text/42/1382a#a_2_B + - title: SSA POMS SI 00830.225 Railroad Retirement Payments + href: https://secure.ssa.gov/poms.nsf/lnx/0500830225 diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/income/ssi_unearned_income.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/income/ssi_unearned_income.yaml index 84afd5359d1..b5bbf2301bc 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/income/ssi_unearned_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/income/ssi_unearned_income.yaml @@ -26,3 +26,11 @@ retirement_distributions: 1_000 output: ssi_unearned_income: 1_000 + +- name: SSI unearned income counts railroad retirement annuities. + period: 2026 + input: + railroad_benefits: 10_800 + output: + # 42 U.S.C. 1382a(a)(2)(B) lists "railroad retirement annuities and pensions". + ssi_unearned_income: 10_800 diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/ssi.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/ssi.yaml index 68611615b0d..7dcb18b2f94 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/ssi.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/ssi.yaml @@ -1,5 +1,6 @@ # Unit tests for SSI variable (final benefit calculation) -# These tests only use the direct inputs to the ssi variable +# The first tests only use the direct inputs to the ssi variable; the railroad +# retirement cases at the end run the full income calculation. # Note: The 'abolish_ssi' parameter test would need a reform, which is not # supported in the current test framework for YAML tests. This would need to be @@ -25,3 +26,33 @@ uncapped_ssi: -100 output: ssi: 0 + +- name: A railroad retirement annuity reduces an aged divorced spouse's SSI. + period: 2026 + absolute_error_margin: 0.01 + input: + age: 70 + # 900 a month, near the RRB's September 2025 average divorced spouse + # annuity of 893.35 (Quarterly Benefit Statistics, Table 1). + railroad_benefits: 10_800 + output: + # (900 - 20 general exclusion) x 12 = 10,560. + ssi_countable_income: 10_560 + # 2026 federal benefit rate of 994 x 12 = 11,928; 11,928 - 10,560 = 1,368. + uncapped_ssi: 1_368 + ssi: 1_368 + +- name: The average railroad retirement employee annuity leaves an aged retiree no SSI. + period: 2026 + absolute_error_margin: 0.01 + input: + age: 70 + # RRB News Release 25-8: the average regular employee annuity is 3,636 a + # month in January 2026; 3,636 x 12 = 43,632. + railroad_benefits: 43_632 + output: + # (3,636 - 20 general exclusion) x 12 = 43,392. + ssi_countable_income: 43_392 + # 11,928 - 43,392 = -31,464. + uncapped_ssi: -31_464 + ssi: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/doe/fap/nh_fap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/doe/fap/nh_fap_countable_income.yaml index aab8c32eef7..7a1a24def53 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nh/doe/fap/nh_fap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/doe/fap/nh_fap_countable_income.yaml @@ -816,7 +816,8 @@ nh_fap_countable_income: 12_000 # Manual pp15,17 deduct the Medicare premium withheld from railroad retirement. -# railroad_benefits is not an SSI unearned source in the model, so MSP status +# Railroad retirement counts as SSI unearned income for MSP, and 1,500 - 20 = +# 1,480 a month is within the MSP limit (about 1,838 a month), so MSP status # turns on assets: 20,000 exceeds the 9,950 MSP resource limit and the enrollee # pays the 2027 premium of 202.90 * 12 = 2,434.80. 18,000 - 2,434.80 = 15,565.20. - name: "Case 28, the Part B premium withheld from railroad retirement is deducted." From 8e96a5bd1d0353461c42e8ebec5db2f4d981bf17 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 29 Oct 2026 10:40:12 -0400 Subject: [PATCH 2/3] Document railroad benefit input and WDP limitation Relabel railroad_benefits, give it a USD unit and document that it holds gross Railroad Retirement Board payments before Medicare premiums or other withholding. Note in the California 250% Working Disabled Program exempt list that railroad disability annuities cannot be separated from other railroad payments, so they now count (follow-up issue 10540). Correct the 2027 Medicare Savings Program limit in the NH fuel assistance test comments to about 1,848 a month. Co-Authored-By: Claude Opus 5.5 --- .../chhs/wdp/eligibility/income/sources/disability.yaml | 5 +++++ .../gov/states/nh/doe/fap/nh_fap_countable_income.yaml | 8 ++++---- .../income/person/retirement/railroad_benefits.py | 8 +++++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ca/chhs/wdp/eligibility/income/sources/disability.yaml b/policyengine_us/parameters/gov/states/ca/chhs/wdp/eligibility/income/sources/disability.yaml index cdb3535351f..1f99fe3cf96 100644 --- a/policyengine_us/parameters/gov/states/ca/chhs/wdp/eligibility/income/sources/disability.yaml +++ b/policyengine_us/parameters/gov/states/ca/chhs/wdp/eligibility/income/sources/disability.yaml @@ -4,6 +4,11 @@ values: - social_security_disability - disability_benefits - workers_compensation + # NOTE: railroad_benefits is not listed. The exemption covers Railroad + # Retirement disability annuities until they convert to age annuities at + # full retirement age, but the input does not separate disability annuities + # from age, spouse or survivor annuities, so every railroad payment counts. + # https://github.com/PolicyEngine/policyengine-us/issues/10540 metadata: unit: list diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/doe/fap/nh_fap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/doe/fap/nh_fap_countable_income.yaml index 7a1a24def53..90b0b480a34 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nh/doe/fap/nh_fap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/doe/fap/nh_fap_countable_income.yaml @@ -790,7 +790,7 @@ # Manual p17 deducts Medicare premiums withheld from Social Security. Social # Security of 12,000 is 1,000 a month, or 980 after the $20 exclusion, within the # Medicare Savings Program limit (135% of the 2027 one-person guideline, about -# 1,838 a month), so MSP pays the premium and nothing is withheld or deducted. +# 1,848 a month), so MSP pays the premium and nothing is withheld or deducted. - name: "Case 27, no Part B deduction applies when the Medicare Savings Program pays the premium." period: 2027 absolute_error_margin: 0.01 @@ -817,7 +817,7 @@ # Manual pp15,17 deduct the Medicare premium withheld from railroad retirement. # Railroad retirement counts as SSI unearned income for MSP, and 1,500 - 20 = -# 1,480 a month is within the MSP limit (about 1,838 a month), so MSP status +# 1,480 a month is within the MSP limit (about 1,848 a month), so MSP status # turns on assets: 20,000 exceeds the 9,950 MSP resource limit and the enrollee # pays the 2027 premium of 202.90 * 12 = 2,434.80. 18,000 - 2,434.80 = 15,565.20. - name: "Case 28, the Part B premium withheld from railroad retirement is deducted." @@ -846,7 +846,7 @@ nh_fap_countable_income: 15_565.2 # Manual pp14-17 allow support paid and the withheld Medicare premium separately. -# Social Security of 2,000 a month is above the MSP limit (about 1,838 a month), +# Social Security of 2,000 a month is above the MSP limit (about 1,848 a month), # so the premium is 2,434.80: 24,000 - 2,000 - 2,434.80 = 19,565.20. - name: "Case 29, support paid and the Part B premium are both deducted." period: 2027 @@ -901,7 +901,7 @@ # Manual p17 and plan item 1.9 count Social Security net of the Medicare deduction. # An enrollee aged 70 needs no reported amount: 1,980 a month after the $20 -# exclusion is above the MSP limit (about 1,838), so the premium is +# exclusion is above the MSP limit (about 1,848), so the premium is # 202.90 * 12 = 2,434.80 and 24,000 - 2,434.80 = 21,565.20. - name: "Case 31, a Medicare enrollee's Part B premium is deducted from Social Security." period: 2027 diff --git a/policyengine_us/variables/household/income/person/retirement/railroad_benefits.py b/policyengine_us/variables/household/income/person/retirement/railroad_benefits.py index 459b96e9cc0..6bb3f290142 100644 --- a/policyengine_us/variables/household/income/person/retirement/railroad_benefits.py +++ b/policyengine_us/variables/household/income/person/retirement/railroad_benefits.py @@ -4,6 +4,12 @@ class railroad_benefits(Variable): value_type = float entity = Person - label = "Recieves any railroad benefits" + label = "Railroad Retirement Board benefits" + unit = USD definition_period = YEAR + documentation = ( + "Gross annual benefits paid by the Railroad Retirement Board, such as " + "retirement, disability, spouse and survivor annuities, before Medicare " + "premiums or other amounts are withheld." + ) default_value = 0 From c8a1d69d56515dd42c782e9822d064349be8945e Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 30 Oct 2026 12:37:07 -0400 Subject: [PATCH 3/3] Count railroad payments for Colorado OAP and address review Add railroad_benefits to the Colorado Old Age Pension unearned income list (9 CCR 2503-5 3.520.785(B)(5)) with a co_oap test, so the lower SSI no longer raises the OAP grant. Document where Railroad Unemployment Insurance Act benefits are reported, fix the ssi_unearned_income label, and note in the SSI list that household net income, SNAP, HUD and other program lists do not yet count railroad_benefits (issue 10551). Co-Authored-By: Claude Opus 5.5 --- .../ssi-railroad-retirement-income.fixed.md | 2 +- .../gov/ssa/ssi/income/sources/unearned.yaml | 4 ++++ .../co/ssa/oap/income/sources/unearned.yaml | 1 + .../gov/states/co/ssa/oap/co_oap.yaml | 20 +++++++++++++++++++ .../eligibility/income/ssi_unearned_income.py | 2 +- .../person/retirement/railroad_benefits.py | 4 +++- 6 files changed, 30 insertions(+), 3 deletions(-) diff --git a/changelog.d/ssi-railroad-retirement-income.fixed.md b/changelog.d/ssi-railroad-retirement-income.fixed.md index 0389133a050..5d70f9b7d5c 100644 --- a/changelog.d/ssi-railroad-retirement-income.fixed.md +++ b/changelog.d/ssi-railroad-retirement-income.fixed.md @@ -1 +1 @@ -Count railroad retirement annuities as unearned income for Supplemental Security Income. +Count railroad retirement annuities as unearned income for Supplemental Security Income and the Colorado Old Age Pension. diff --git a/policyengine_us/parameters/gov/ssa/ssi/income/sources/unearned.yaml b/policyengine_us/parameters/gov/ssa/ssi/income/sources/unearned.yaml index a764c21789e..9492706d3be 100644 --- a/policyengine_us/parameters/gov/ssa/ssi/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/ssa/ssi/income/sources/unearned.yaml @@ -4,6 +4,10 @@ values: # (a) Annuities, pensions, and other periodic payments. - pension_income - social_security + # NOTE: Household net income, SNAP, HUD annual income and other program + # income lists count social_security and ssi but not railroad_benefits, so + # an SSI recipient's railroad annuity drops out of them. + # https://github.com/PolicyEngine/policyengine-us/issues/10551 - railroad_benefits - disability_benefits - veterans_benefits diff --git a/policyengine_us/parameters/gov/states/co/ssa/oap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/co/ssa/oap/income/sources/unearned.yaml index f22838c36a2..7fc10e34b61 100644 --- a/policyengine_us/parameters/gov/states/co/ssa/oap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/co/ssa/oap/income/sources/unearned.yaml @@ -9,6 +9,7 @@ values: 2020-03-01: - pension_income - social_security + - railroad_benefits - disability_benefits - veterans_benefits - survivor_benefits diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/ssa/oap/co_oap.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/ssa/oap/co_oap.yaml index 5afc06b3ef2..bc22a7ef8df 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/ssa/oap/co_oap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/ssa/oap/co_oap.yaml @@ -552,3 +552,23 @@ output: co_oap_own_countable_income: 8_760.12 co_oap: 3_612 + +- name: Case 36, a Railroad Retirement annuity counts as unearned income. + # 3.520.785(B)(5) counts Railroad Retirement Board payments. 900/month, near + # the RRB's September 2025 average divorced spouse annuity of 893.35, less the + # $20 disregard is 880; SSI pays 994 - 880 = 114; 1,032 - 114 - 880 = 38, + # raised to 189. + period: 2026 + input: + people: + person: + age: 70 + railroad_benefits: 10_800 + households: + household: + members: [person] + state_code: CO + output: + ssi: 1_368 + co_oap_countable_income: 10_560 + co_oap: 2_268 diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ssi_unearned_income.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ssi_unearned_income.py index 11911c9f16e..ed55916fd72 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ssi_unearned_income.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ssi_unearned_income.py @@ -4,7 +4,7 @@ class ssi_unearned_income(Variable): value_type = float entity = Person - label = "SSI earned income" + label = "SSI unearned income" unit = USD definition_period = YEAR diff --git a/policyengine_us/variables/household/income/person/retirement/railroad_benefits.py b/policyengine_us/variables/household/income/person/retirement/railroad_benefits.py index 6bb3f290142..65278a26348 100644 --- a/policyengine_us/variables/household/income/person/retirement/railroad_benefits.py +++ b/policyengine_us/variables/household/income/person/retirement/railroad_benefits.py @@ -10,6 +10,8 @@ class railroad_benefits(Variable): documentation = ( "Gross annual benefits paid by the Railroad Retirement Board, such as " "retirement, disability, spouse and survivor annuities, before Medicare " - "premiums or other amounts are withheld." + "premiums or other amounts are withheld. Railroad Unemployment Insurance " + "Act benefits are reported elsewhere: unemployment benefits in " + "unemployment_compensation and sickness benefits in disability_benefits." ) default_value = 0