diff --git a/changelog.d/ri-ssp-2026.added.md b/changelog.d/ri-ssp-2026.added.md new file mode 100644 index 00000000000..6e7facd29bf --- /dev/null +++ b/changelog.d/ri-ssp-2026.added.md @@ -0,0 +1 @@ +Add Rhode Island optional state SSI supplements and institutional payments, verified for 2026. diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index d2cbd6ba2d4..51f6ec638dd 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -67,6 +67,8 @@ values: - sc_child_care_subsidies # New Mexico benefits - nm_ssi_state_supplement + # Rhode Island benefits + - ri_ssp # South Carolina benefits - sc_ssi_state_supplement # Texas benefits @@ -159,6 +161,8 @@ values: - ok_child_care_subsidies # New Mexico benefits - nm_ssi_state_supplement + # Rhode Island benefits + - ri_ssp # South Carolina benefits - sc_ssi_state_supplement # Texas benefits @@ -261,6 +265,8 @@ values: - ok_child_care_subsidies # New Mexico benefits - nm_ssi_state_supplement + # Rhode Island benefits + - ri_ssp # South Carolina benefits - sc_ssi_state_supplement # Texas benefits @@ -364,6 +370,8 @@ values: - ok_child_care_subsidies # New Mexico benefits - nm_ssi_state_supplement + # Rhode Island benefits + - ri_ssp # South Carolina benefits - sc_ssi_state_supplement # Texas benefits @@ -401,6 +409,7 @@ values: - nj_property_tax_relief # New York benefits - ny_child_care_subsidies + metadata: unit: list period: year diff --git a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml index 0df11213631..21b96b582c6 100644 --- a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml @@ -19,6 +19,7 @@ values: - strike_benefits - social_security - ssi + - ri_ssp - general_assistance - total_unemployment_compensation - child_support_received @@ -29,6 +30,7 @@ values: - disability_benefits - survivor_benefits - financial_assistance + metadata: unit: list period: year diff --git a/policyengine_us/parameters/gov/ssa/ssi/state_supplement/minimum_payment.yaml b/policyengine_us/parameters/gov/ssa/ssi/state_supplement/minimum_payment.yaml new file mode 100644 index 00000000000..1d3e6e2e6b6 --- /dev/null +++ b/policyengine_us/parameters/gov/ssa/ssi/state_supplement/minimum_payment.yaml @@ -0,0 +1,13 @@ +description: The Social Security Administration pays at least this monthly amount to each recipient of a positive federally administered optional state supplement. +values: + 2026-01-01: 1 + +metadata: + unit: currency-USD + period: month + label: SSI optional state supplement minimum payment + reference: + - title: 20 CFR 416.2020(c) - Minimum federally administered supplementary payment + href: https://www.ssa.gov/OP_Home/cfr20/416/416-2020.htm + - title: POMS SI 02001.005 A.2 and B.2 - Minimum benefit for individuals and members of couples + href: https://secure.ssa.gov/poms.nsf/lnx/0502001005 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ssp/amount/couple.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ssp/amount/couple.yaml new file mode 100644 index 00000000000..255a1a49165 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ssp/amount/couple.yaml @@ -0,0 +1,42 @@ +description: Rhode Island provides these amounts as the monthly couple payment under the State Supplementary Payment program. + +metadata: + unit: currency-USD + period: month + label: Rhode Island SSP couple amount + breakdown: + - ri_ssp_living_arrangement + reference: + - title: R.I. Gen. Laws § 40-6-27(a)(1)(iii), (iv), (v), (a)(3) + href: https://webserver.rilegislature.gov/Statutes/TITLE40/40-6/40-6-27.htm + - title: "218-RICR-20-00-5, Sections 5.1.1.A.3, 5.1.1.B.1 and 5.6.A #page 1,13" + href: https://risos-apa-production-public.s3.amazonaws.com/DHS/REG_13426_20260109151518643.pdf#page=1 + - title: POMS SI BOS01415.012 B.1, Rhode Island residential care/assisted living (D) + href: https://secure.ssa.gov/poms.nsf/lnx/0501415012BOS + - title: 20 CFR 416.2025(b)(3) + href: https://www.law.cornell.edu/cfr/text/20/416.2025#b_3 + +INDEPENDENT: + 2026-01-01: 79.38 + +HOUSEHOLD_OF_ANOTHER: + 2026-01-01: 97.3 + +# Category D applies to adult individuals only and has no couple rate +# (POMS SI BOS01415.012 B.1; 218-RICR-20-00-5 Section 5.6.A lists N/A), so +# ri_ssp pays a member of an eligible couple the Category A rate instead. +# This entry equals the individual rate so that the ineligible-spouse +# comparison of the higher couple or individual rate (20 CFR 416.2025(b)(3); +# POMS SI 01320.430 C.7) uses the individual rate. +RESIDENTIAL_CARE: + 2026-01-01: 332 + +# Category E covers an individual or couple in a Title XIX facility +# (218-RICR-20-00-5 Section 5.1.1.A.3.c) and pays the personal needs +# allowance to each individual (R.I. Gen. Laws § 40-6-27(a)(3)), so the +# couple entry is twice the individual rate. +MEDICAID_INSTITUTION: + 2026-01-01: 90 + +NONE: + 2026-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ssp/amount/individual.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ssp/amount/individual.yaml new file mode 100644 index 00000000000..533ea73760c --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ssp/amount/individual.yaml @@ -0,0 +1,30 @@ +description: Rhode Island provides these amounts as the monthly individual payment under the State Supplementary Payment program. + +metadata: + unit: currency-USD + period: month + label: Rhode Island SSP individual amount + breakdown: + - ri_ssp_living_arrangement + reference: + - title: R.I. Gen. Laws § 40-6-27(a)(1)(i), (ii), (v), (a)(3) + href: https://webserver.rilegislature.gov/Statutes/TITLE40/40-6/40-6-27.htm + - title: 218-RICR-20-00-5, Section 5.6.A + href: https://risos-apa-production-public.s3.amazonaws.com/DHS/REG_13426_20260109151518643.pdf#page=13 + - title: POMS SI 01415.058 L.2, Rhode Island Category D federally administered January 2026 payment level + href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#l2 + +INDEPENDENT: + 2026-01-01: 39.92 + +HOUSEHOLD_OF_ANOTHER: + 2026-01-01: 51.92 + +RESIDENTIAL_CARE: + 2026-01-01: 332 + +MEDICAID_INSTITUTION: + 2026-01-01: 45 + +NONE: + 2026-01-01: 0 diff --git a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml index e9baee603e8..cf3c2c8d3f4 100644 --- a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml @@ -47,6 +47,7 @@ values: - mo_ssp - ne_aabd - nm_ssi_state_supplement + - ri_ssp - sc_ssi_state_supplement - tx_ssi_state_supplement - wa_ssp @@ -95,9 +96,7 @@ values: metadata: reference: - - title: 7 CFR 273.9(b)(2) - href: https://www.law.cornell.edu/cfr/text/7/273.9#b_2 - - title: 7 CFR 273.9(c)(1) - href: https://www.law.cornell.edu/cfr/text/7/273.9#c_1 + - title: 7 CFR 273.9(b)(2) and (c)(1) + href: https://www.law.cornell.edu/cfr/text/7/273.9 - title: POMS SI 01401.001 General Information about State Supplementation href: https://secure.ssa.gov/poms.nsf/lnx/0501401001 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 5250ab3aa89..b8831b12bd6 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1093,6 +1093,18 @@ programs: tracks. Unmodeled paths: grandfathered medically-needy-in-medical- institution recipients per WAC 388-478-0055(2)(b); DDA-determined / PVL track per (2)(f); and foster child in BRS per (2)(g). + - state: RI + status: partial + name: Rhode Island SSP + full_name: Rhode Island State Supplementary Payment + variable: ri_ssp + parameter_prefix: gov.states.ri.dhs.ssp + verified_years: "2026" + notes: >- + Models 2026 optional living-arrangement supplements and Title XIX + facility personal-needs payments. Mandatory grandfathered payments, + facility subsidies and the statutory supportive residential-care + category are not modeled. - id: social_security name: Social Security diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/integration.yaml new file mode 100644 index 00000000000..a8fe9842bcc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/integration.yaml @@ -0,0 +1,185 @@ +- name: Case 1, independent couple. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + person2: + age: 65 + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Both spouses are aged, so the SSI couple computation applies. + ssi_couple_computation_applies: [true, true] + ri_ssp_living_arrangement: [INDEPENDENT, INDEPENDENT] + ssi_countable_income: [0, 0] + # Federal couple rate: 1_491 / 2 = 745.50 each + ssi_amount_if_eligible: [745.5, 745.5] + ssi: [745.5, 745.5] + # Category A couple rate: 79.38 / 2 = 39.69 each + ri_ssp: [39.69, 39.69] + +- name: Case 2, couple living in another person's household. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + person2: + age: 65 + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ssi_federal_living_arrangement: [ANOTHER_PERSONS_HOUSEHOLD, ANOTHER_PERSONS_HOUSEHOLD] + ri_ssp_living_arrangement: [HOUSEHOLD_OF_ANOTHER, HOUSEHOLD_OF_ANOTHER] + ssi_couple_computation_applies: [true, true] + # The one-third reduction lowers the rate; no in-kind support is counted. + ssi_countable_income: [0, 0] + # Federal: 1_491 / 2 = 745.50 * (1 - 1/3) = 497 each + ssi_amount_if_eligible: [497, 497] + ssi: [497, 497] + # Category B couple rate: 97.30 / 2 = 48.65 each + ri_ssp: [48.65, 48.65] + +- name: Case 3, annual benefits and SNAP income. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + output: + ssi_countable_income: 0 + # Federal: 994 * 12 = 11_928 + ssi_amount_if_eligible: 11_928 + ssi: 11_928 + # Category A individual rate: 39.92 * 12 = 479.04 + ri_ssp: 479.04 + household_state_benefits: 479.04 + # SSI plus the supplement: 11_928 + 479.04 = 12_407.04 + snap_unearned_income: 12_407.04 + hud_unearned_income: 12_407.04 + +- name: Case 4, couple with Social Security above the federal couple rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 12_600 + person2: + age: 68 + social_security_retirement: 6_000 + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ssi_couple_computation_applies: [true, true] + ri_ssp_living_arrangement: [INDEPENDENT, INDEPENDENT] + # Monthly Social Security: 12_600 / 12 = 1_050 and 6_000 / 12 = 500 + ssi_unearned_income: [1_050, 500] + # Couple countable income: 1_050 + 500 - 20 = 1_530; 1_530 / 2 = 765 each + ssi_countable_income: [765, 765] + ssi_amount_if_eligible: [745.5, 745.5] + # 745.50 - 765 = -19.50, so federal SSI is exhausted. + uncapped_ssi: [-19.5, -19.5] + ssi: [0, 0] + # Category A: 39.69 - (765 - 745.50) = 39.69 - 19.50 = 20.19 each + ri_ssp: [20.19, 20.19] + +- name: Case 5, aged worker with part-time earnings. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 67 + employment_income: 25_200 + output: + ri_ssp_living_arrangement: INDEPENDENT + # Earnings: 25_200 / 12 = 2_100 per month + ssi_earned_income: 2_100 + # No unearned income, so the $20 general exclusion applies to earnings: + # (2_100 - 20 - 65) * 0.5 = 1_007.50 + ssi_countable_income: 1_007.5 + ssi_amount_if_eligible: 994 + # 994 - 1_007.50 = -13.50, so federal SSI is exhausted. + uncapped_ssi: -13.5 + ssi: 0 + # Category A: 39.92 - (1_007.50 - 994) = 39.92 - 13.50 = 26.42 + ri_ssp: 26.42 + +- name: Case 6, assisted living resident with an ineligible spouse. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + ri_ssp_certified_residential_care: true + person2: + age: 63 + social_security_retirement: 19_200 + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Both spouses live together in the assisted living residence, so + # person2's income is deemed to person1 (20 CFR 416.1160(a)(1)). + # person2 is under 65 and not blind or disabled, so there is no joint + # claim and person1 stays in Category D. + ssi_couple_computation_applies: [false, false] + ri_ssp_living_arrangement: [RESIDENTIAL_CARE, INDEPENDENT] + is_ssi_eligible: [true, false] + # Spouse income: 19_200 / 12 = 1_600 per month, above the + # 1_491 - 994 = 497 deeming threshold. + # Deemed income: (0 + 1_600 - 20) - 0 = 1_580 + ssi_income_deemed_from_ineligible_spouse: [1_580, 0] + ssi_countable_income: [1_580, 0] + # Deeming uses the couple rate; person2 is not an eligible individual. + ssi_amount_if_eligible: [1_491, 994] + # 1_491 - 1_580 = -89, so federal SSI is exhausted. + uncapped_ssi: [-89, 0] + ssi: [0, 0] + # Own income alone: 332 - max(0 - 994, 0) = 332 + # With deeming: max(332, 332) - (1_580 - 1_491) = 332 - 89 = 243 + # Category D pays the lower amount: min(332, 243) = 243. SSI is 0, so + # DHS pays it as a state-only supplement; 243 is a whole dollar. + ri_ssp: [243, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/ri_ssp.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/ri_ssp.yaml new file mode 100644 index 00000000000..14dc8528a58 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/ri_ssp.yaml @@ -0,0 +1,380 @@ +# RI: 218-RICR-20-00-5; R.I. Gen. Laws § 40-6-27; POMS SI 01415.058 and SI BOS01415.012. +- name: Case 1, independent living. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + output: + ri_ssp: 39.92 + +- name: Case 2, living in household of another. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + output: + ri_ssp: 51.92 + +- name: Case 3, certified residential care. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + ri_ssp_certified_residential_care: true + output: + ri_ssp: 332 + +- name: Case 4, medical institution. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + output: + ri_ssp: 45 + +- name: Case 5, SSI exhausted but state payment remains. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + social_security_retirement: 12_360 + output: + ri_ssp: 23.92 + +- name: Case 6, state administered payment below a dollar. + period: 2026-01 + absolute_error_margin: 0.001 + input: + state_code: RI + age: 65 + social_security_retirement: 12_642 + output: + # Countable income: 12_642 / 12 = 1_053.50 - 20 = 1_033.50 + # Excess over the FBR: 1_033.50 - 994 = 39.50 + # Category A: 39.92 - 39.50 = 0.42; the state pays no $1 minimum. + ri_ssp: 0.42 + +- name: Case 7, combined income cutoff. + period: 2026-01 + absolute_error_margin: 0.001 + input: + state_code: RI + age: 65 + social_security_retirement: 18_000 + output: + # Countable income: 18_000 / 12 = 1_500 - 20 = 1_480 + # 1_480 exceeds the combined standard of 994 + 39.92 = 1_033.92. + ri_ssp: 0 + +- name: Case 8, excess resources. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + ssi_countable_resources: 2_001 + output: + ri_ssp: 0 + +- name: Case 9, not aged blind or disabled. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 30 + output: + ri_ssp: 0 + +- name: Case 10, nonresident. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: OH + age: 65 + output: + ri_ssp: 0 + +- name: Case 11, declines required SSI application. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + takes_up_ssi_if_eligible: false + output: + ri_ssp: 0 + +- name: Case 12, institutional state only payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 65 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + social_security_retirement: 720 + output: + ri_ssp: 35 + +- name: Case 13, married couple in assisted living with a joint claim. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + ri_ssp_certified_residential_care: true + person2: + age: 72 + ri_ssp_certified_residential_care: true + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Category D is for adult individuals only, so the couple is paid as + # Category A: couple rate 79.38 / 2 = 39.69 each, state administered. + ri_ssp: [39.69, 39.69] + +- name: Case 14, couple with only one spouse in certified care. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + person2: + age: 72 + ri_ssp_certified_residential_care: true + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # person1 is in the own household category; person2's certified care + # falls back to Category A in an eligible couple. + # Couple rate: (79.38 / 2 + 79.38 / 2) / 2 = 39.69 each. + ri_ssp: [39.69, 39.69] + +- name: Case 15, disabled child with the certified care input. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: RI + age: 16 + is_disabled: true + meets_ssi_disability_criteria: true + ri_ssp_certified_residential_care: true + output: + # Category D does not apply to children, so the Category A individual + # rate applies, paid by the state: 39.92. + ri_ssp: 39.92 + +- name: Case 16, state-only assisted living payment below a dollar. + period: 2026-01 + absolute_error_margin: 0.001 + input: + state_code: RI + age: 80 + social_security_retirement: 16_146 + ri_ssp_certified_residential_care: true + output: + # Countable income: 16_146 / 12 = 1_345.50 - 20 = 1_325.50 + # Excess over the FBR: 1_325.50 - 994 = 331.50, so no federal SSI. + ssi: 0 + # 218-RICR-20-00-5 Sections 5.1.1.A.1 and 5.2.B.3: DHS pays the + # state-only supplement, 332 - 331.50 = 0.50, with no $1 minimum. + ri_ssp: 0.5 + +- name: Case 17, reported SSI recipient's Category D payment is federally administered. + period: 2026-01 + absolute_error_margin: 0.001 + input: + state_code: RI + age: 80 + social_security_retirement: 16_146 + receives_ssi: true + ri_ssp_certified_residential_care: true + output: + # SSA pays Category D to SSI recipients and raises 0.50 to $1 + # (20 CFR 416.2020(c)). + ri_ssp: 1 + +- name: Case 18, married couple in a Title XIX facility. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + person2: + age: 78 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 20 CFR 416.414(b)(2): 60 / 2 = 30 each. + ssi: [30, 30] + # R.I. Gen. Laws § 40-6-27(a)(3) pays each individual 45; couple 90 / 2. + ri_ssp: [45, 45] + +- name: Case 19, own household with an ineligible spouse receiving Social Security. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + person2: + age: 63 + # $1,000 a month. + social_security_retirement: 12_000 + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 1_000 is above the 497 deeming threshold; 1_000 - 20 = 980 deemed. + ssi_countable_income: [980, 0] + # Federal: the lesser of 994 and 1_491 - 980 = 511. + ssi: [511, 0] + # State: the lesser of 39.92 and the couple rate 79.38 with no excess + # over the couple FBR (POMS SI 01320.430 D.2.c, D.3.b). + ri_ssp: [39.92, 0] + +- name: Case 20, own household with an ineligible spouse whose income exhausts both payments. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + person2: + age: 63 + # $2,000 a month. + social_security_retirement: 24_000 + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ssi_countable_income: [1_980, 0] + ssi: [0, 0] + # max(79.38, 39.92) - (1_980 - 1_491) < 0 (20 CFR 416.2025(b)(3)). + ri_ssp: [0, 0] + +- name: Case 21, mixed household-of-another and own-household inputs for a couple average the two rates. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + person2: + age: 70 + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ssp_living_arrangement: [HOUSEHOLD_OF_ANOTHER, INDEPENDENT] + # A couple living together shares one federal living arrangement (20 CFR + # 416.1131(a)-(b)), so this mix does not arise in Rhode Island. The case + # pins only the POMS SI 02005.030 G.1 averaging: + # (97.30 / 2 + 79.38 / 2) / 2 = 44.17 each. + ri_ssp: [44.17, 44.17] + +- name: Case 22, certified care for one of two unrelated recipients leaves the other's category. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + person2: + age: 80 + ri_ssp_certified_residential_care: true + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + unit1: + members: [person1] + unit2: + members: [person2] + households: + home1: + members: [person1] + state_code: RI + home2: + members: [person2] + state_code: RI + output: + ri_ssp_living_arrangement: [INDEPENDENT, RESIDENTIAL_CARE] + ri_ssp: [39.92, 332] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/ri_ssp_living_arrangement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/ri_ssp_living_arrangement.yaml new file mode 100644 index 00000000000..2bb16744ea3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ssp/ri_ssp_living_arrangement.yaml @@ -0,0 +1,84 @@ +# RI: 218-RICR-20-00-5 Section 5.1.1. Certified care comes from +# ri_ssp_certified_residential_care; ri_ssp.yaml tests its couple and child +# fallback. +- name: Case 1, own household. + period: 2026-01 + input: + state_code: RI + age: 65 + output: + ri_ssp_living_arrangement: INDEPENDENT + +- name: Case 2, household of another with shelter and all meals provided. + period: 2026-01 + input: + state_code: RI + age: 65 + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + output: + ri_ssp_living_arrangement: HOUSEHOLD_OF_ANOTHER + +- name: Case 3, Medicaid pays most of the facility care. + period: 2026-01 + input: + state_code: RI + age: 65 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + output: + ri_ssp_living_arrangement: MEDICAID_INSTITUTION + +- name: Case 4, facility resident without majority Medicaid payment. + period: 2026-01 + input: + state_code: RI + age: 65 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: false + output: + # Not a Title XIX facility placement, so the own household category applies. + ri_ssp_living_arrangement: INDEPENDENT + +- name: Case 5, nonresident. + period: 2026-01 + input: + state_code: OH + age: 65 + output: + ri_ssp_living_arrangement: NONE + +- name: Case 6, certified residential care. + period: 2026-01 + input: + state_code: RI + age: 80 + ri_ssp_certified_residential_care: true + output: + ri_ssp_living_arrangement: RESIDENTIAL_CARE + +- name: Case 7, Title XIX facility takes precedence over certified care. + period: 2026-01 + input: + state_code: RI + age: 80 + ri_ssp_certified_residential_care: true + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + output: + # Category D is used with federal living arrangement A only (POMS SI + # BOS01415.012 B.1). + ri_ssp_living_arrangement: MEDICAID_INSTITUTION + +- name: Case 8, certified care takes precedence over the household-of-another inputs. + period: 2026-01 + input: + state_code: RI + age: 80 + ri_ssp_certified_residential_care: true + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + output: + ri_ssp_living_arrangement: RESIDENTIAL_CARE diff --git a/policyengine_us/variables/gov/ssa/ssi/_ssi_state_supplement.py b/policyengine_us/variables/gov/ssa/ssi/_ssi_state_supplement.py new file mode 100644 index 00000000000..5e0c84da3f3 --- /dev/null +++ b/policyengine_us/variables/gov/ssa/ssi/_ssi_state_supplement.py @@ -0,0 +1,53 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.ssa.ssi.eligibility.status.ssi_federal_living_arrangement import ( + SSIFederalLivingArrangement, +) + + +def ssi_state_supplement( + person, period, parameters, individual_rate, couple_rate, federal_payment_rules=True +): + """Apply SSI-based supplement income, couple and spouse-deeming rules. + + Rates are state supplements, excluding federal SSI. Each member supplies + the same-category couple rate; averaging these rates implements mixed + arrangements where the state's published schedule supports that method. + Set federal_payment_rules only for SSA-administered payments; state + administrators do not inherit the federal rounding or minimum payment. + Sources: 20 CFR 416.2025; POMS SI 01320.430 D, SI 02005.030 G, + SI 02001.005 and SI 02001.010. Callers apply state-specific eligibility. + """ + joint = person("ssi_couple_computation_applies", period) + couple_total = person.marital_unit.sum(couple_rate / 2) + standard = where(joint, couple_total / 2, individual_rate) + countable = person("ssi_countable_income", period) + federal_amount = person("ssi_amount_if_eligible", period) + excess = max_(countable - federal_amount, 0) + payment = max_(standard - excess, 0) + + deeming = person("is_ssi_spousal_deeming_applies", period.this_year) + deemed = person("ssi_income_deemed_from_ineligible_spouse", period) + own_income = max_(countable - deemed, 0) + ssi = parameters(period).gov.ssa.ssi + federal_la = person("ssi_federal_living_arrangement", period) + own_federal_amount = ssi.amount.individual * where( + federal_la == SSIFederalLivingArrangement.ANOTHER_PERSONS_HOUSEHOLD, + 1 - ssi.amount.one_third_reduction_rate, + 1, + ) + own_payment = max_(individual_rate - max_(own_income - own_federal_amount, 0), 0) + # SI 01320.430 D.2: use the higher individual rate where it exceeds + # the couple rate (including New Jersey's ineligible-spouse variation). + deemed_payment = max_(max_(couple_rate, individual_rate) - excess, 0) + payment = where(deeming, min_(own_payment, deemed_payment), payment) + + eligible = person("is_ssi_eligible", period) & person( + "takes_up_ssi_if_eligible", period.this_year + ) + # Federal administration discards digits beyond the third decimal place, + # rounds up to cents, and pays at least one dollar for a positive amount. + rounded = np.ceil(np.floor(payment * 1_000) / 10) / 100 + federal_payment = where( + rounded > 0, max_(rounded, ssi.state_supplement.minimum_payment), 0 + ) + return eligible * where(federal_payment_rules, federal_payment, payment) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp.py b/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp.py new file mode 100644 index 00000000000..3b17d889131 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp.py @@ -0,0 +1,60 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.ssa.ssi._ssi_state_supplement import ( + ssi_state_supplement, +) + + +class ri_ssp(Variable): + value_type = float + entity = Person + label = "Rhode Island State Supplementary Payment" + unit = USD + definition_period = MONTH + defined_for = StateCode.RI + reference = ( + "https://webserver.rilegislature.gov/Statutes/TITLE40/40-6/40-6-27.htm", + # 218-RICR-20-00-5, Sections 5.1.1, 5.2.B.3, 5.3.A.2, 5.3.B.1 and 5.6 + # PDF pages 1, 3-4, 6-7, 13 + "https://risos-apa-production-public.s3.amazonaws.com/DHS/REG_13426_20260109151518643.pdf#page=1", + # POMS SI BOS01415.012 B.1: Category D is for adult individuals only + "https://secure.ssa.gov/poms.nsf/lnx/0501415012BOS", + # POMS SI 01415.058 L.2: federally administered Category D payment level + "https://secure.ssa.gov/poms.nsf/lnx/0501415058#l2", + "https://www.law.cornell.edu/cfr/text/20/416.2010", + "https://www.law.cornell.edu/cfr/text/20/416.2020#c", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ri.dhs.ssp.amount + arrangement = person("ri_ssp_living_arrangement", period) + arrangements = arrangement.possible_values + # Category D applies to adult individuals only. A child or a member of + # an eligible couple with certified care is paid as Category A (POMS + # SI BOS01415.012 B.1; SI BOS01415.950 A.3). + certified_care = arrangement == arrangements.RESIDENTIAL_CARE + child = person("is_child", period.this_year) + joint = person("ssi_couple_computation_applies", period) + category_d = certified_care & ~child & ~joint + own_household = certified_care & ~category_d + individual = where( + own_household, p.individual.INDEPENDENT, p.individual[arrangement] + ) + couple = where(own_household, p.couple.INDEPENDENT, p.couple[arrangement]) + # SSA pays Category D only to SSI recipients (218-RICR-20-00-5 Section + # 5.1.1.B). DHS pays a resident denied SSI for excess income as a + # state-only supplement (Sections 5.1.1.A.1, 5.2.B.3 and 5.3.A.2), + # without the rounding or $1 minimum that 20 CFR 416.2020(c) applies to + # federally administered payments. + # NOTE: 20 CFR 416.2025(b)(3) and the POMS SI 01415.058 L total of + # $1,326 also fit SSA paying supplement-only cases, but 20 CFR + # 416.2010(a)(1) leaves that coverage to the State, so this follows the + # state regulation. + receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) + return ssi_state_supplement( + person, + period, + parameters, + individual, + couple, + federal_payment_rules=category_d & receives_ssi, + ) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp_certified_residential_care.py b/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp_certified_residential_care.py new file mode 100644 index 00000000000..ba041968d05 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp_certified_residential_care.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ri_ssp_certified_residential_care(Variable): + value_type = bool + entity = Person + label = "Certified for Rhode Island SSP residential care or assisted living" + definition_period = MONTH + defined_for = StateCode.RI + reference = ( + # 218-RICR-20-00-5, Section 5.2.B.2.a + "https://risos-apa-production-public.s3.amazonaws.com/DHS/REG_13426_20260109151518643.pdf#page=3", + "https://secure.ssa.gov/poms.nsf/lnx/0501415012BOS", + # POMS SI 01415.058 L.1: OS code D only for DHS-certified residents + "https://secure.ssa.gov/poms.nsf/lnx/0501415058#l1", + ) + documentation = "Screened, assessed and certified by DHS as residing in a residential care or assisted living facility, including residents exempt from certification because they received this payment level in October or November 1998." diff --git a/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp_living_arrangement.py b/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp_living_arrangement.py new file mode 100644 index 00000000000..96bc98645bd --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ssp/ri_ssp_living_arrangement.py @@ -0,0 +1,64 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.ssa.ssi.eligibility.status.ssi_federal_living_arrangement import ( + SSIFederalLivingArrangement, +) + + +class RISSPLivingArrangement(Enum): + # NOTE: R.I. Gen. Laws § 40-6-27(a)(1)(vii) lists a $300 supplement for + # state-licensed supportive residential-care settings. 218-RICR-20-00-5 + # Section 5.6 and SSA's 2026 payment levels publish no such category, so + # it is not modeled. + INDEPENDENT = "Own household" + HOUSEHOLD_OF_ANOTHER = "Household of another" + RESIDENTIAL_CARE = "State-certified residential care or assisted living" + MEDICAID_INSTITUTION = "Title XIX facility" + NONE = "No supplement" + + +class ri_ssp_living_arrangement(Variable): + value_type = Enum + entity = Person + label = "Rhode Island SSP living arrangement" + definition_period = MONTH + defined_for = StateCode.RI + possible_values = RISSPLivingArrangement + default_value = RISSPLivingArrangement.NONE + reference = ( + # 218-RICR-20-00-5, Section 5.1.1 + "https://risos-apa-production-public.s3.amazonaws.com/DHS/REG_13426_20260109151518643.pdf#page=1", + "https://secure.ssa.gov/poms.nsf/lnx/0501415012BOS", + "https://secure.ssa.gov/poms.nsf/lnx/0501415950BOS", + ) + documentation = """ + Certified care comes from ri_ssp_certified_residential_care. Category D + applies to adult individuals only, so ri_ssp pays a child or a member of an + eligible couple with certified care at the own-household rate. When + institutional residence ends eligible-couple status, set ssi_claim_is_joint + (a yearly formula variable) to false for both spouses; an input replaces the + formula for everyone in the simulation, so set it to true for any other + joint couple. Certified care itself does not override federal SSI claim or + income calculations. Certified residents are in federal living arrangement + A (POMS SI BOS01415.012 B.1), so do not also set the household-of-another + SSI inputs for them. + """ + + def formula(person, period, parameters): + federal = person("ssi_federal_living_arrangement", period) + # Category D is used with federal living arrangement A only (POMS SI + # BOS01415.012 B.1), so a Title XIX facility resident is Category E. + # Certified residents are in federal arrangement A, so certified care + # precedes the household of another. + return select( + [ + federal == SSIFederalLivingArrangement.MEDICAL_TREATMENT_FACILITY, + person("ri_ssp_certified_residential_care", period), + federal == SSIFederalLivingArrangement.ANOTHER_PERSONS_HOUSEHOLD, + ], + [ + RISSPLivingArrangement.MEDICAID_INSTITUTION, + RISSPLivingArrangement.RESIDENTIAL_CARE, + RISSPLivingArrangement.HOUSEHOLD_OF_ANOTHER, + ], + default=RISSPLivingArrangement.INDEPENDENT, + ) diff --git a/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py b/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py index a473c2b438d..b56ebc96457 100644 --- a/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py +++ b/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py @@ -22,6 +22,7 @@ def formula(spm_unit, period, parameters): "ky_ssp", # Kentucky benefits "de_ssp", # Delaware benefits "fl_oss", + "ri_ssp", # Rhode Island benefits "ks_sspp", # Kansas benefits "hi_oss", "la_oss", # Louisiana benefits