diff --git a/changelog.d/or-ssp-2026.added.md b/changelog.d/or-ssp-2026.added.md new file mode 100644 index 00000000000..2b4c2c7bb0f --- /dev/null +++ b/changelog.d/or-ssp-2026.added.md @@ -0,0 +1 @@ +Add Oregon State Supplemental Payment 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..eddf8b576c2 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -63,6 +63,8 @@ values: - nv_child_care_subsidies # Oklahoma benefits - ok_child_care_subsidies + # Oregon benefits + - or_ssp # South Carolina benefits - sc_child_care_subsidies # New Mexico benefits @@ -157,6 +159,8 @@ values: - nv_child_care_subsidies # Oklahoma benefits - ok_child_care_subsidies + # Oregon benefits + - or_ssp # New Mexico benefits - nm_ssi_state_supplement # South Carolina benefits @@ -259,6 +263,8 @@ values: - nv_child_care_subsidies # Oklahoma benefits - ok_child_care_subsidies + # Oregon benefits + - or_ssp # New Mexico benefits - nm_ssi_state_supplement # South Carolina benefits @@ -362,6 +368,8 @@ values: - nv_child_care_subsidies # Oklahoma benefits - ok_child_care_subsidies + # Oregon benefits + - or_ssp # New Mexico benefits - nm_ssi_state_supplement # South Carolina 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..6581156e8b8 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 + - or_ssp_countable_for_hud - 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/states/or/odhs/ssp/excluded_income_sources.yaml b/policyengine_us/parameters/gov/states/or/odhs/ssp/excluded_income_sources.yaml new file mode 100644 index 00000000000..31ec0e3b287 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/odhs/ssp/excluded_income_sources.yaml @@ -0,0 +1,15 @@ +description: Oregon excludes these income sources from countable income under the State Supplemental Payment program. +values: + 2018-04-01: + - interest_income + - dividend_income + +metadata: + unit: list + period: year + label: Oregon SSP excluded income sources + reference: + - title: OAR 461-145-0030(4) + href: https://ch461rules.odhs.oregon.gov/rules/461-145-0030.pdf#page=2 + - title: OAR 461-145-0108(1)(a) + href: https://ch461rules.odhs.oregon.gov/rules/461-145-0108.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/or/odhs/ssp/in_home_amount.yaml b/policyengine_us/parameters/gov/states/or/odhs/ssp/in_home_amount.yaml new file mode 100644 index 00000000000..894ded26f79 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/odhs/ssp/in_home_amount.yaml @@ -0,0 +1,11 @@ +description: Oregon provides this amount as the monthly in-home supplement under the State Supplemental Payment program. +values: + 2016-01-01: 22 + +metadata: + unit: currency-USD + period: month + label: Oregon SSP in-home reimbursement + reference: + - title: OAR 461-155-0575(2) + href: https://ch461rules.odhs.oregon.gov/rules/461-155-0575.pdf diff --git a/policyengine_us/parameters/gov/states/or/odhs/ssp/nursing_facility_payment_standard.yaml b/policyengine_us/parameters/gov/states/or/odhs/ssp/nursing_facility_payment_standard.yaml new file mode 100644 index 00000000000..ae1dcd0d5e9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/odhs/ssp/nursing_facility_payment_standard.yaml @@ -0,0 +1,18 @@ +description: Oregon pays a nursing facility resident the difference between countable income and this amount under the State Supplemental Payment program. +values: + # NOTE: 461-155-0250(4)(c) prints $79.07, while (4)(b) (effective 1-01-26) + # and transmittal OEP-PT-25-045 (effective 1/1/2026) raise the personal + # incidentals allowance to $81.28. Every version with subsection (c), from + # 7-01-14 to 1-01-25, used one figure in (b) and (c). The model follows the + # text of (4)(c). + 2026-01-01: 79.07 + +metadata: + unit: currency-USD + period: month + label: Oregon SSP nursing facility payment standard + reference: + - title: "OAR 461-155-0250(4)(c) #page 1-2" + href: https://ch461rules.odhs.oregon.gov/rules/461-155-0250.pdf#page=1 + - title: ODHS transmittal OEP-PT-25-045 + href: https://www.oregon.gov/odhs/transmittals/oeptransmittals/pt25045.pdf#page=8 diff --git a/policyengine_us/parameters/gov/states/or/odhs/ssp/reduced_va_pension.yaml b/policyengine_us/parameters/gov/states/or/odhs/ssp/reduced_va_pension.yaml new file mode 100644 index 00000000000..1c0cbc05ec2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/odhs/ssp/reduced_va_pension.yaml @@ -0,0 +1,13 @@ +description: Oregon limits the nursing-facility restoration payment to recipients whose reduced Veterans pension is at most this amount under the State Supplemental Payment program. +values: + 2020-01-01: 90 + +metadata: + unit: currency-USD + period: month + label: Oregon SSP reduced VA pension limit + reference: + - title: OAR 461-155-0700(1)(b) + href: https://ch461rules.odhs.oregon.gov/rules/461-155-0700.pdf#page=1 + - title: OAR 461-155-0700 history, version effective 1-01-20 + href: https://ch461rules.odhs.oregon.gov/historical/461-155-0700_history.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/or/odhs/ssp/room_and_board.yaml b/policyengine_us/parameters/gov/states/or/odhs/ssp/room_and_board.yaml new file mode 100644 index 00000000000..b4a84ab0e54 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/odhs/ssp/room_and_board.yaml @@ -0,0 +1,13 @@ +description: Oregon sets this amount as the monthly community-based care room and board standard under the State Supplemental Payment program. +values: + 2026-01-01: 773 + +metadata: + unit: currency-USD + period: month + label: Oregon OSIPM room and board standard + reference: + - title: OAR 461-155-0270 + href: https://ch461rules.odhs.oregon.gov/rules/461-155-0270.pdf + - title: OEP-PT-25-045, January 2026 standards + href: https://www.oregon.gov/odhs/transmittals/oeptransmittals/pt25045.pdf#page=7 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..76eea95ab11 100644 --- a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml @@ -50,6 +50,10 @@ values: - sc_ssi_state_supplement - tx_ssi_state_supplement - wa_ssp + # Not listed: OAR 461-145-0410(7)(c)(D) excludes Oregon's modeled OSIP + # special need payments (or_ssp) from SNAP income as reimbursements. Its + # nursing facility payment goes to institution residents, who are not SNAP + # households under 7 CFR 273.1(b)(7)(vi). # Listed elsewhere: ca_state_supplement is an SPM unit variable with no # person-level counterpart. policyengine-core projects a group value onto # every member, so listing it here would count it once per person in the @@ -95,9 +99,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..2f0c5c4e793 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1093,6 +1093,17 @@ 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: OR + status: partial + name: Oregon SSP + full_name: Oregon State Supplemental Payment + variable: or_ssp + parameter_prefix: gov.states.or.odhs.ssp + verified_years: "2026" + notes: Models 2026 OSIPM in-home, SSI couple community care, transitional personal + incidentals/room and board, spousal diversion, special room-and-board and nursing + facility personal incidentals payments. Other special needs and historical mandatory + supplements are not modeled. - id: social_security name: Social Security diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/integration.yaml new file mode 100644 index 00000000000..344bb1f05ec --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/integration.yaml @@ -0,0 +1,160 @@ +- name: Case 1, couple SSI recipients in care. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + or_ssp_category: COMMUNITY_CARE + person2: + age: 65 + or_ssp_category: COMMUNITY_CARE + marital_units: + couple: + members: [person1, person2] + households: + hh: + members: [person1, person2] + state_code: OR + output: + or_ssp: [248.5, 248.5] + +- name: Case 2, excess income of spouse offsets other spouse. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + or_ssp_category: COMMUNITY_CARE + # $1,200 a month. + social_security_retirement: 14_400 + person2: + age: 65 + or_ssp_category: COMMUNITY_CARE + marital_units: + couple: + members: [person1, person2] + households: + hh: + members: [person1, person2] + state_code: OR + output: + # Couple computation: 1,491 / 2 = 745.50 each. + ssi_amount_if_eligible: [745.5, 745.5] + # Couple SSI: 1,491 - (1,200 - 20) = 311, or 155.50 each. + ssi: [155.5, 155.5] + # person1: 1,200 + 155.50 = 1,355.50; person2: 155.50. + or_ssp_countable_income: [1_355.5, 155.5] + # person1: 994 - 1,355.50 < 0, so 0; excess 1,355.50 - 994 = 361.50. + # person2: 994 - 155.50 - 361.50 = 477. + or_ssp: [0, 477] + +- name: Case 3, both spouses must receive SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + or_ssp_category: COMMUNITY_CARE + person2: + age: 65 + or_ssp_category: COMMUNITY_CARE + takes_up_ssi_if_eligible: false + marital_units: + couple: + members: [person1, person2] + households: + hh: + members: [person1, person2] + state_code: OR + output: + # person2 does not receive SSI, so OAR 461-155-0630(3) does not apply. + or_ssp: [0, 0] + +- name: Case 4, both spouses must have community care. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + or_ssp_category: COMMUNITY_CARE + person2: + age: 65 + or_ssp_category: NONE + marital_units: + couple: + members: [person1, person2] + households: + hh: + members: [person1, person2] + state_code: OR + output: + or_ssp: [0, 0] + +- name: Case 5, in-home reimbursement excluded from SNAP and HUD income. + period: 2026 + absolute_error_margin: 0.01 + input: + age: 65 + state_code: OR + or_ssp_category: IN_HOME + output: + or_ssp: 264 + household_state_benefits: 264 + snap_unearned_income: 11_928 + hud_unearned_income: 11_928 + +- name: Case 6, community care payment counts as HUD but not SNAP unearned income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + or_ssp_category: COMMUNITY_CARE + # $1,200 a month. + social_security_retirement: 14_400 + person2: + age: 65 + or_ssp_category: COMMUNITY_CARE + marital_units: + couple: + members: [person1, person2] + households: + hh: + members: [person1, person2] + state_code: OR + output: + # Case 2 monthly amounts for 12 months: SSI 155.50 * 12 = 1,866 each. + ssi: [1_866, 1_866] + # person2: 477 * 12 = 5,724. + or_ssp: [0, 5_724] + # Community care is not the in-home reimbursement, so HUD counts it. + or_ssp_countable_for_hud: [0, 5_724] + # OAR 461-145-0410(7)(c)(D) excludes the special need from SNAP: + # 12 * (1,200 Social Security + 311 SSI) = 18,132. + snap_unearned_income: 18_132 + # person1: 14,400 Social Security + 1,866 SSI = 16,266. + # person2: 1,866 SSI + 5,724 SSP = 7,590. + hud_unearned_income: [16_266, 7_590] + +- name: Case 7, temporary absence without a care liability counts all countable income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + age: 65 + state_code: OR + or_ssp_category: ROOM_BOARD_ABSENCE + # $500 a month. + social_security_retirement: 6_000 + output: + # SSI: 994 - (500 - 20) = 514. + ssi: 514 + # 514 SSI + 500 Social Security = 1,014. + or_ssp_countable_income: 1_014 + # No care liability, so all 1,014 is available for room and board. + # 773 room and board standard - 1,014 < 0, so no payment. + or_ssp: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/or_ssp.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/or_ssp.yaml new file mode 100644 index 00000000000..0aeb7eef1f5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/or_ssp.yaml @@ -0,0 +1,542 @@ +- name: Case 1, no certified services. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + output: + or_ssp: 0 + +- name: Case 2, approved in-home SSI-only recipient. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: IN_HOME + output: + or_ssp: 22 + +- name: Case 3, Social Security income disqualifies the in-home supplement. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: IN_HOME + # $500 a month. + social_security_retirement: 6_000 + output: + # SSI: 994 - (500 - 20) = 514; countable income 514 + 500 = 1,014. + # 1,014 is not SSI alone, so no in-home supplement. + or_ssp: 0 + +- name: Case 4, part-time earnings disqualify the in-home supplement. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: IN_HOME + # 10 hours a week at Oregon's $15.05 standard minimum wage (July 2025): + # 15.05 * 10 * 52 = 7,826 a year, or 652.17 a month. + employment_income: 7_826 + output: + # SSI: 994 - (652.17 - 20 - 65) * 0.5 = 994 - 283.58 = 710.42. + # Countable income 710.42 + 652.17 = 1,362.58 is not SSI alone, so 0. + or_ssp: 0 + +- name: Case 5, excluded bank interest does not disqualify. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: IN_HOME + interest_income: 120 + output: + or_ssp: 22 + +- name: Case 6, in-home supplement requires SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: IN_HOME + ssi: 0 + output: + or_ssp: 0 + +- name: Case 7, disability interim assistance. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 40 + or_ssp_category: DISABILITY_INTERIM + ssi: 0 + output: + or_ssp: 994 + +- name: Case 8, interim amount uses countable not adjusted income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 40 + or_ssp_category: DISABILITY_INTERIM + ssi: 0 + employment_income: 1_200 + output: + or_ssp: 894 + +- name: Case 9, SSI restored after institutional payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: SSI_RESTORATION + ssi: 30 + output: + or_ssp: 964 + +- name: Case 10, full SSI ends restoration gap. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: SSI_RESTORATION + output: + or_ssp: 0 + +- name: Case 11, reduced VA pension restoration. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: VA_RESTORATION + ssi: 0 + veterans_benefits: 1_080 + output: + or_ssp: 904 + +- name: Case 12, pursuing naturalization after SSI time limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: NATURALIZATION + ssi: 0 + output: + or_ssp: 994 + +- name: Case 13, suspended SSI gets room and board only. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: SUSPENDED_SSI + ssi: 0 + output: + or_ssp: 773 + +- name: Case 14, suspension allowance ends when SSI restarts. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: SUSPENDED_SSI + output: + or_ssp: 0 + +- name: Case 15, January sixteen day restoration grant. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: SSI_RESTORATION + ssi: 30 + or_ssp_partial_month_days: 16 + output: + or_ssp: 497.5483870967742 + +- name: Case 16, February fourteen day interim grant. + period: 2026-02 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 40 + or_ssp_category: DISABILITY_INTERIM + ssi: 0 + or_ssp_partial_month_days: 14 + output: + or_ssp: 497 + +- name: Case 17, eligible days covering the whole month pay the full amount. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: IN_HOME + or_ssp_partial_month_days: 31 + output: + or_ssp: 22 + +- name: Case 18, spousal diversion includes income shortfall. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: SPOUSAL_DIVERSION + ssi: 0 + social_security_retirement: 9_600 + or_ssp_spousal_diversion_difference: 100 + output: + or_ssp: 294 + +- name: Case 19, spousal diversion above standard. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: SPOUSAL_DIVERSION + ssi: 0 + social_security_retirement: 14_400 + or_ssp_spousal_diversion_difference: 100 + output: + or_ssp: 100 + +- name: Case 20, temporary absence uses income available after care liability. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: ROOM_BOARD_ABSENCE + # $1,200 a month, so no SSI. + social_security_retirement: 14_400 + # 1,200 less the $81.28 nursing facility personal needs allowance + # (OEP-PT-25-045; OAR 461-155-0250(4)(b)). + or_ssp_care_liability: 1_118.72 + output: + # 773 - (1,200 - 1,118.72) = 691.72. + or_ssp: 691.72 + +- name: Case 21, incapacity payment uses accessible income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: ROOM_BOARD_INCAPACITY + # $1,200 a month of Social Security that cannot be accessed. + social_security_retirement: 14_400 + or_ssp_inaccessible_income: 1_200 + output: + # SSI is 0, and the inaccessible income is not countable. + or_ssp_countable_income: 0 + or_ssp: 773 + +- name: Case 22, approved initial placement room and board. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: INITIAL_ROOM_BOARD + or_ssp_approved_initial_room_board: 500 + output: + or_ssp: 500 + +- name: Case 23, initial placement payment capped at published amount. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: INITIAL_ROOM_BOARD + or_ssp_approved_initial_room_board: 900 + output: + or_ssp: 773 + +- name: Case 24, nonresident. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WA + age: + 2026: 65 + or_ssp_category: IN_HOME + output: + or_ssp: 0 + +- name: Case 25, reported SSI receipt qualifies for the in-home supplement when modeled SSI is zero. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: IN_HOME + ssi: 0 + receives_ssi: true + output: + # Reported receipt meets the SSI condition; countable income 0 equals SSI 0. + or_ssp: 22 + +- name: Case 26, reported SSI receipt is not a suspended SSI payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: SUSPENDED_SSI + ssi: 0 + receives_ssi: true + output: + # SSI is reported as received, so it is not suspended and the 773 + # room and board allowance (Case 13) does not apply. + or_ssp: 0 + +- name: Case 27, unmarried community care recipient gets no couple payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 65 + or_ssp_category: COMMUNITY_CARE + output: + # OAR 461-155-0630(3) covers only spouses who each receive SSI. + ssi: 994 + or_ssp: 0 + +- name: Case 28, spouses paid SSI as individuals get no couple payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + or_ssp_category: COMMUNITY_CARE + person2: + age: 65 + or_ssp_category: COMMUNITY_CARE + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + households: + household1: + members: [person1] + state_code: OR + household2: + members: [person2] + state_code: OR + output: + # Living apart, each receives the individual rate, so countable income + # equals the 994 standard. + ssi: [994, 994] + or_ssp: [0, 0] + +- name: Case 29, nursing facility resident on SSI receives the personal incidentals payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 80 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + output: + ssi: 30 + # OAR 461-155-0250(4)(c): 79.07 - 30 = 49.07. + or_ssp: 49.07 + +- name: Case 30, nursing facility resident with Social Security above the payment standard. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 80 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + # $1,200 a month. + social_security_retirement: 14_400 + output: + ssi: 0 + or_ssp: 0 + +- name: Case 31, nursing facility resident with a reduced $90 VA pension. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: OR + age: + 2026: 80 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + # OAR 461-155-0250(4)(a): $90 a month. + veterans_benefits: 1_080 + # POMS SI 00830.308 B: the reduced $90 pension is not SSI income. + ssi: 30 + output: + # 461-155-0250(4)(c) covers only (4)(b) residents, and countable income + # 30 + 90 = 120 exceeds 79.07, so 0. + or_ssp_countable_income: 120 + or_ssp: 0 + +- name: Case 32, partial-month days for one resident leave another resident's full month. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + or_ssp_category: SSI_RESTORATION + ssi: 30 + or_ssp_partial_month_days: 16 + person2: + age: 65 + or_ssp_category: SSI_RESTORATION + ssi: 30 + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: OR + output: + # 964 * 16 / 31 = 497.55 and the full 964. + or_ssp: [497.5483870967742, 964] + +- name: Case 33, care liability for one absent resident leaves another resident's income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + or_ssp_category: ROOM_BOARD_ABSENCE + social_security_retirement: 14_400 + or_ssp_care_liability: 1_118.72 + person2: + age: 65 + or_ssp_category: ROOM_BOARD_ABSENCE + social_security_retirement: 14_400 + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_code: OR + output: + # person1: 773 - (1,200 - 1,118.72) = 691.72. person2 has no liability, + # and 773 - 1,200 < 0. + or_ssp: [691.72, 0] + +- name: Case 34, partial-month days entered for one month leave the next month full. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: OR + age: 65 + or_ssp_category: IN_HOME + or_ssp_partial_month_days: + 2026-01: 16 + output: + or_ssp_partial_month_days: + 2026-01: 16 + 2026-02: 0 + # January: 22 * 16 / 31 = 11.35; February is a full month: 22. + or_ssp: + 2026-01: 11.354838709677419 + 2026-02: 22 diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py new file mode 100644 index 00000000000..80da0a570b1 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py @@ -0,0 +1,107 @@ +from policyengine_us.model_api import * + + +class or_ssp(Variable): + value_type = float + entity = Person + label = "Oregon State Supplemental Payment" + definition_period = MONTH + unit = USD + reference = ( + # ORS 411.704(1)(b), 411.706(1) + "https://www.oregonlegislature.gov/bills_laws/ors/ors411.html", + # PDF pages 1-2 + "https://ch461rules.odhs.oregon.gov/rules/461-155-0250.pdf#page=1", + "https://ch461rules.odhs.oregon.gov/rules/461-155-0575.pdf", + # PDF pages 1-3 + "https://ch461rules.odhs.oregon.gov/rules/461-155-0630.pdf#page=1", + # PDF pages 1-3 + "https://ch461rules.odhs.oregon.gov/rules/461-155-0700.pdf#page=1", + "https://ch461rules.odhs.oregon.gov/rules/461-160-0070.pdf", + # 461-101-0010(17) defines OSIP as these special need payments. + "https://ch461rules.odhs.oregon.gov/rules/461-101-0010.pdf#page=3", + # DHS 2818 (10/2026) + "https://sharedsystems.dhsoha.state.or.us/DHSForms/Served/de2818.pdf#page=583", + ) + defined_for = StateCode.OR + + def formula(person, period, parameters): + p = parameters(period).gov.states["or"].odhs.ssp + federal = parameters(period).gov.ssa.ssi.amount + # The OSIPM one-person adjusted income standard in OAR 461-155-0250(3) + # currently equals the SSI federal benefit rate ($994 in 2026). + standard = federal.individual + category = person("or_ssp_category", period) + c = category.possible_values + income = person("or_ssp_countable_income", period) + ssi = person("ssi", period) + receives_ssi = (ssi > 0) | person("receives_ssi", period) + in_home = (category == c.IN_HOME) & receives_ssi & (income == ssi) + # Community care and SSI restoration amounts depend on the SSI payment, + # so those paths require modeled SSI rather than reported receipt. + care = (category == c.COMMUNITY_CARE) & (ssi > 0) + couple = person.marital_unit.sum(care) == 2 + own_excess = max_(income - standard, 0) + spouse_excess = person.marital_unit.sum(own_excess) - own_excess + couple_payment = max_(standard - income - spouse_excess, 0) + interim = (category == c.DISABILITY_INTERIM) | (category == c.NATURALIZATION) + restoring_ssi = ( + (category == c.SSI_RESTORATION) + & (ssi > 0) + & (ssi <= federal.medical_facility) + ) + veterans = person("veterans_benefits", period) + restoring_va = ( + (category == c.VA_RESTORATION) + & (veterans > 0) + & (veterans <= p.reduced_va_pension) + ) + suspended = (category == c.SUSPENDED_SSI) & ~receives_ssi + diversion = max_(person("or_ssp_spousal_diversion_difference", period), 0) + absence = category == c.ROOM_BOARD_ABSENCE + incapacity = category == c.ROOM_BOARD_INCAPACITY + # 461-155-0630(2)(b)(A)(iv): a temporary absence uses the income left + # after contributing to the care liability. + liability = max_(person("or_ssp_care_liability", period), 0) + room_board_income = where(absence, max_(income - liability, 0), income) + # 461-155-0250(4)(c): an OSIPM nursing facility or ICF-ID resident + # receives the payment standard minus countable income (including + # SSI). A $90 VA pension already exceeds it. + # NOTE: SSI receipt stands in for OSIPM eligibility, so residents + # without SSI whose countable income is $50 to $79.07 are not modeled. + # The SSI medical treatment facility arrangement also includes + # hospitals, and OSIPM-EPD residents are not excluded. A temporary + # absence from community-based care pays only the room and board + # payment. + arrangement = person("ssi_federal_living_arrangement", period) + nursing_facility = ( + arrangement == arrangement.possible_values.MEDICAL_TREATMENT_FACILITY + ) & receives_ssi + amount = select( + [ + in_home, + care & couple, + interim | restoring_ssi | restoring_va, + suspended | absence | incapacity, + category == c.SPOUSAL_DIVERSION, + nursing_facility, + ], + [ + p.in_home_amount, + couple_payment, + max_(standard - income, 0), + max_(p.room_and_board - room_board_income, 0), + diversion + max_(standard - income, 0), + max_(p.nursing_facility_payment_standard - income, 0), + ], + default=0, + ) + days = person("or_ssp_partial_month_days", period) + partial_month = (days > 0) & (days < period.days) + # 461-160-0070 uses actual calendar days and does not round the result. + prorated = where(partial_month, amount * days / period.days, amount) + initial = min_( + max_(person("or_ssp_approved_initial_room_board", period), 0), + p.room_and_board, + ) + return where(category == c.INITIAL_ROOM_BOARD, initial, prorated) diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_approved_initial_room_board.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_approved_initial_room_board.py new file mode 100644 index 00000000000..ce881a5ad7d --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_approved_initial_room_board.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class or_ssp_approved_initial_room_board(Variable): + value_type = float + entity = Person + label = "Oregon approved initial placement room and board payment" + definition_period = MONTH + unit = USD + reference = ("https://ch461rules.odhs.oregon.gov/rules/461-155-0630.pdf#page=1",) + documentation = "Approved payment for the covered initial placement period after the state assesses the unmet need; zero unless provided." diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_care_liability.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_care_liability.py new file mode 100644 index 00000000000..4251b0f0f9f --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_care_liability.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class or_ssp_care_liability(Variable): + value_type = float + entity = Person + label = "Oregon SSP care liability during a temporary absence" + definition_period = MONTH + unit = USD + defined_for = StateCode.OR + reference = ( + "https://ch461rules.odhs.oregon.gov/rules/461-155-0630.pdf#page=2", + # PDF pages 1, 3-4 + "https://ch461rules.odhs.oregon.gov/rules/461-160-0620.pdf#page=1", + ) + documentation = "Liability owed under OAR 461-160-0620 during an approved temporary absence from a community-based care facility. Leave at 0 when none is owed." diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_category.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_category.py new file mode 100644 index 00000000000..609ce24a42a --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_category.py @@ -0,0 +1,46 @@ +from policyengine_us.model_api import * + + +class ORSSPCategory(Enum): + IN_HOME = "Approved SSI-only in-home services" + COMMUNITY_CARE = "Approved licensed community care with an SSI spouse" + DISABILITY_INTERIM = ( + "State disability determination while pursuing SSI through final appeal" + ) + SSI_RESTORATION = "Leaving nursing care and pursuing full SSI restoration" + VA_RESTORATION = "Leaving nursing care and pursuing full VA pension restoration" + NATURALIZATION = "Qualified noncitizen pursuing naturalization after SSI time limit" + SUSPENDED_SSI = ( + "Leaving a public institution and pursuing suspended SSI reinstatement" + ) + SPOUSAL_DIVERSION = "Approved additional community-spouse diversion" + ROOM_BOARD_ABSENCE = "Approved temporary absence with intent to return" + ROOM_BOARD_INCAPACITY = ( + "Approved inaccessible-income case pending representative appointment" + ) + INITIAL_ROOM_BOARD = "Approved initial placement room and board" + NONE = "No approved OSIPM special need" + + +class or_ssp_category(Variable): + value_type = Enum + entity = Person + label = "Oregon SSP approved special need category" + definition_period = MONTH + possible_values = ORSSPCategory + default_value = ORSSPCategory.NONE + reference = ( + "https://ch461rules.odhs.oregon.gov/rules/461-155-0575.pdf", + # PDF pages 1-3 + "https://ch461rules.odhs.oregon.gov/rules/461-155-0630.pdf#page=1", + # PDF pages 1-3 + "https://ch461rules.odhs.oregon.gov/rules/461-155-0700.pdf#page=1", + ) + documentation = """ + Select only after OSIPM financial eligibility, placement/service authorization, + lack of other resources to meet the need, and the category's procedural + requirements are established. Includes approval of temporary-absence and + incapacity extensions. Change to NONE when authorization or required + pursuit of benefits ends. Specialized care eligibility is not inferred + from ordinary Medicaid enrollment. + """ diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_hud.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_hud.py new file mode 100644 index 00000000000..0315fd154c6 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_hud.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class or_ssp_countable_for_hud(Variable): + value_type = float + entity = Person + label = "Oregon SSP countable for HUD" + definition_period = MONTH + unit = USD + defined_for = StateCode.OR + reference = ( + # 24 CFR 5.609(b)(19) + "https://www.law.cornell.edu/cfr/text/24/5.609", + # DHS 2818 (10/2026) + "https://sharedsystems.dhsoha.state.or.us/DHSForms/Served/de2818.pdf#page=583", + ) + documentation = "The Oregon SSP payment without the in-home supplement, which reimburses uncovered assistance needs of a person receiving in-home services." + + def formula(person, period, parameters): + category = person("or_ssp_category", period) + in_home = category == category.possible_values.IN_HOME + return where(in_home, 0, person("or_ssp", period)) diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_income.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_income.py new file mode 100644 index 00000000000..d1350188688 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_income.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class or_ssp_countable_income(Variable): + value_type = float + entity = Person + label = "Oregon SSP countable income before deductions" + definition_period = MONTH + unit = USD + reference = ( + # PDF pages 1, 5 + "https://ch461rules.odhs.oregon.gov/rules/461-001-0000.pdf#page=1", + "https://ch461rules.odhs.oregon.gov/rules/461-145-0030.pdf#page=2", + "https://ch461rules.odhs.oregon.gov/rules/461-145-0108.pdf#page=1", + "https://ch461rules.odhs.oregon.gov/rules/461-140-0040.pdf#page=4", + ) + documentation = "Includes SSI and countable cash income before the general or earnings deductions. Investment interest and dividends and income inaccessible due to incapacity are excluded. Other state exclusions and countable loan interest are not modeled." + + def formula(person, period, parameters): + p = parameters(period).gov + sources = p.ssa.ssi.income.sources + excluded = p.states["or"].odhs.ssp.excluded_income_sources + income = person("ssi", period) + for name in list(sources.earned) + list(sources.unearned): + if name not in excluded: + income = income + max_(person(name, period), 0) + # OAR 461-140-0040(5)(e)(D): income inaccessible due to incapacity is + # unavailable, so it is not countable. + inaccessible = max_(person("or_ssp_inaccessible_income", period), 0) + return max_(income - inaccessible, 0) diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_inaccessible_income.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_inaccessible_income.py new file mode 100644 index 00000000000..c17e05cd661 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_inaccessible_income.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class or_ssp_inaccessible_income(Variable): + value_type = float + entity = Person + label = "Oregon SSP income inaccessible due to incapacity" + definition_period = MONTH + unit = USD + defined_for = StateCode.OR + reference = ( + "https://ch461rules.odhs.oregon.gov/rules/461-140-0040.pdf#page=4", + # PDF pages 2-3 + "https://ch461rules.odhs.oregon.gov/rules/461-155-0630.pdf#page=2", + ) + documentation = "Income that an individual determined eligible for community-based care or nursing facility services cannot access due to incapacity while a legal or financial representative is being established, approved as unavailable for up to three months under OAR 461-140-0040(5)(e)(D). Leave at 0 otherwise, including for in-home services." diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_partial_month_days.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_partial_month_days.py new file mode 100644 index 00000000000..9c7c3ddfb31 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_partial_month_days.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class or_ssp_partial_month_days(Variable): + value_type = int + entity = Person + label = "Oregon SSP eligible days in a partial month" + definition_period = MONTH + defined_for = StateCode.OR + reference = ( + "https://ch461rules.odhs.oregon.gov/rules/461-160-0070.pdf", + "https://ch461rules.odhs.oregon.gov/rules/461-155-0700.pdf#page=3", + ) + documentation = "Days of eligibility in a month of less than full eligibility. Leave at 0 for a full month. Enter it for the month, since a yearly value applies to every month. An approved initial room-and-board payment is already the amount for the covered period." + + def formula(person, period, parameters): + # A formula stops a one-month input from carrying into later months. + return 0 diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_spousal_diversion_difference.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_spousal_diversion_difference.py new file mode 100644 index 00000000000..17be97ab0df --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_spousal_diversion_difference.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class or_ssp_spousal_diversion_difference(Variable): + value_type = float + entity = Person + label = "Oregon additional diversion available under nursing facility placement" + definition_period = MONTH + unit = USD + reference = ("https://ch461rules.odhs.oregon.gov/rules/461-155-0700.pdf#page=2",) + documentation = "State-calculated excess of permitted nursing-facility diversion over community-care diversion, using 461-160-0620 liability rules. Requires an approved request under 461-155-0700(1)(d)." 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..6d15f421f74 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", + "or_ssp", # Oregon benefits "ks_sspp", # Kansas benefits "hi_oss", "la_oss", # Louisiana benefits