From de2c41f6199511aac40135bc9c6e112eae1840e5 Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 12 Oct 2026 14:27:23 -0400 Subject: [PATCH 1/5] Add Oregon state supplementation for 2026 --- changelog.d/or-ssp-2026.added.md | 1 + .../household/household_state_benefits.yaml | 4 + .../hud/annual_income/sources/unearned.yaml | 3 +- .../states/or/odhs/ssp/in_home_amount.yaml | 11 + .../or/odhs/ssp/reduced_va_pension.yaml | 11 + .../states/or/odhs/ssp/room_and_board.yaml | 10 + .../usda/snap/income/sources/unearned.yaml | 13 +- policyengine_us/programs.yaml | 12 + .../gov/states/or/odhs/ssp/integration.yaml | 120 ++++++++ .../gov/states/or/odhs/ssp/or_ssp.yaml | 288 ++++++++++++++++++ .../gov/states/or/odhs/ssp/or_ssp.py | 76 +++++ .../ssp/or_ssp_approved_initial_room_board.py | 13 + .../ssp/or_ssp_available_room_board_income.py | 16 + .../gov/states/or/odhs/ssp/or_ssp_category.py | 44 +++ .../or/odhs/ssp/or_ssp_countable_for_snap.py | 18 ++ .../or/odhs/ssp/or_ssp_countable_income.py | 25 ++ .../or/odhs/ssp/or_ssp_days_eligible.py | 15 + .../or_ssp_spousal_diversion_difference.py | 13 + .../income/spm_unit/spm_unit_benefits.py | 1 + 19 files changed, 686 insertions(+), 8 deletions(-) create mode 100644 changelog.d/or-ssp-2026.added.md create mode 100644 policyengine_us/parameters/gov/states/or/odhs/ssp/in_home_amount.yaml create mode 100644 policyengine_us/parameters/gov/states/or/odhs/ssp/reduced_va_pension.yaml create mode 100644 policyengine_us/parameters/gov/states/or/odhs/ssp/room_and_board.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/integration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/or_ssp.yaml create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_approved_initial_room_board.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_category.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_snap.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_income.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_days_eligible.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_spousal_diversion_difference.py 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..e71f09c9312 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -78,6 +78,7 @@ values: # DC benefits - dc_ossp # Kansas benefits + - or_ssp - ks_sspp # Hawaii benefits - hi_oss @@ -176,6 +177,7 @@ values: # DC benefits - dc_ossp # Kansas benefits + - or_ssp - ks_sspp # Hawaii benefits - hi_oss @@ -279,6 +281,7 @@ values: - dc_ossp - dc_child_care_subsidies # Kansas benefits + - or_ssp - ks_sspp # Hawaii benefits - hi_oss @@ -382,6 +385,7 @@ values: - dc_ossp - dc_child_care_subsidies # Kansas benefits + - or_ssp - ks_sspp # Hawaii benefits - hi_oss 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 d2b2bbd8675..9af17388584 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_snap - general_assistance - unemployment_compensation - child_support_received @@ -34,5 +35,5 @@ metadata: period: year label: HUD unearned income sources reference: - - title: 24 CFR § 5.609(a)(1), (a)(2) + - title: 24 CFR § 5.609(a)(1), (a)(2), (b)(6), (b)(19) href: https://www.law.cornell.edu/cfr/text/24/5.609 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..8f4b0388b39 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/odhs/ssp/in_home_amount.yaml @@ -0,0 +1,11 @@ +description: Oregon provides this monthly reimbursement to SSI-only recipients with authorized in-home + care. +values: + '2016-01-01': 22 +metadata: + unit: currency-USD + label: Oregon SSP in-home reimbursement + reference: + - title: OAR 461-155-0575 + href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf + period: month 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..53e5fafa002 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/odhs/ssp/reduced_va_pension.yaml @@ -0,0 +1,11 @@ +description: Oregon permits the restoration supplement for recipients leaving a nursing facility with + a Veterans benefit no larger than this amount. +values: + '2024-10-01': 90 +metadata: + unit: currency-USD + label: Oregon SSP reduced VA pension limit + reference: + - title: OAR 461-155-0700(1)(b) + href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf + period: month 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..6a7ccbedbb8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/odhs/ssp/room_and_board.yaml @@ -0,0 +1,10 @@ +description: Oregon uses this monthly room and board standard for OSIPM special needs payments. +values: + '2026-01-01': 773 +metadata: + unit: currency-USD + label: Oregon OSIPM room and board standard + reference: + - title: OEP-PT-25-045, January 2026 standards + href: https://www.oregon.gov/odhs/transmittals/oeptransmittals/pt25045.pdf + period: month 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 6f94d3d09b2..66d112647e9 100644 --- a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml @@ -16,9 +16,9 @@ values: # exempts public assistance vendor payments only for medical assistance, # child care, energy assistance, migrant emergency assistance, housing # authority housing assistance, and emergency or special assistance that - # is not the normal grant. None of the supplements below fall in those - # categories, so each counts, whether paid to the recipient or to a - # facility on the recipient's behalf. + # is not the normal grant. Countable components below exclude medical + # reimbursements and state-specific exempt payments; ordinary cash and + # room-and-board supplements count even when paid to a provider. - ak_ssp - al_ssp # co_oap has an annual definition period; policyengine-core's @@ -36,6 +36,7 @@ values: - hi_oss - id_aabd - in_ssp + - or_ssp_countable_for_snap - ks_sspp - ky_ssp - la_oss @@ -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), (5) + 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 05cb1d13747..7155d40381c 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1090,6 +1090,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: 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: OSIPM in-home, SSI couple community care, transitional personal incidentals/room + and board, and approved spousal diversion and special room-and-board payments. Eligibility + and procedural authorization require a certified category; specialized income exclusions, + liability and diversion need explicit inputs. Other medical reimbursements and historical + mandatory supplements are excluded. - 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..23b8a59cf11 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/integration.yaml @@ -0,0 +1,120 @@ +- name: Case 1, couple SSI recipients in care. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + first: + age: 65 + or_ssp_category: COMMUNITY_CARE + second: + age: 65 + or_ssp_category: COMMUNITY_CARE + marital_units: + couple: + members: + - first + - second + households: + hh: + members: + - first + - second + 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: + first: + age: 65 + or_ssp_category: COMMUNITY_CARE + ssi: 700 + or_ssp_countable_income: 1100 + second: + age: 65 + or_ssp_category: COMMUNITY_CARE + ssi: 700 + or_ssp_countable_income: 700 + marital_units: + couple: + members: + - first + - second + households: + hh: + members: + - first + - second + state_code: OR + output: + or_ssp: + - 0 + - 188 +- name: Case 3, both spouses must receive SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + first: + age: 65 + or_ssp_category: COMMUNITY_CARE + second: + age: 65 + or_ssp_category: COMMUNITY_CARE + ssi: 0 + marital_units: + couple: + members: + - first + - second + households: + hh: + members: + - first + - second + state_code: OR + output: + or_ssp: + - 0 + - 0 +- name: Case 4, both spouses must have community care. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + first: + age: 65 + or_ssp_category: COMMUNITY_CARE + second: + age: 65 + or_ssp_category: NONE + marital_units: + couple: + members: + - first + - second + households: + hh: + members: + - first + - second + state_code: OR + output: + or_ssp: + - 0 + - 0 +- name: Case 5, in-home reimbursement excluded from SNAP income. + period: '2026' + absolute_error_margin: 0.01 + input: + age: 65 + state_code: OR + or_ssp_category: IN_HOME + output: + or_ssp: 264 + snap_unearned_income: 11928 + hud_unearned_income: 11928 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..8945959511d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/or/odhs/ssp/or_ssp.yaml @@ -0,0 +1,288 @@ +- 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, ten dollars other cash income disqualifies before deductions. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + '2026': OR + age: + '2026': 65 + or_ssp_category: IN_HOME + social_security_retirement: 120 + output: + or_ssp: 0 +- name: Case 4, small earnings disqualify before deductions. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + '2026': OR + age: + '2026': 65 + or_ssp_category: IN_HOME + employment_income: 120 + output: + 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: 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': 65 + or_ssp_category: DISABILITY_INTERIM + ssi: 0 + employment_income: 1200 + 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: 1080 + 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_days_eligible: 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': 65 + or_ssp_category: DISABILITY_INTERIM + ssi: 0 + or_ssp_days_eligible: 14 + output: + or_ssp: 497 +- name: Case 17, zero eligible days. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + '2026': OR + age: + '2026': 65 + or_ssp_category: IN_HOME + or_ssp_days_eligible: 0 + output: + or_ssp: 0 +- 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: 9600 + 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: 14400 + 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 + or_ssp_available_room_board_income: 200 + output: + or_ssp: 573 +- 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 + or_ssp_available_room_board_income: 0 + output: + 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: WA + age: + '2026': 65 + or_ssp_category: IN_HOME + output: + or_ssp: 0 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..6a49c1d1322 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py @@ -0,0 +1,76 @@ +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 = ( + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-160-0070.pdf", + ) + defined_for = StateCode.OR + + def formula(person, period, parameters): + p = parameters(period).gov.states["or"].odhs.ssp + federal = parameters(period).gov.ssa.ssi.amount + standard = federal.individual + category = person("or_ssp_category", period) + c = category.possible_values + income = person("or_ssp_countable_income", period) + ssi = person("ssi", period) + in_home = (category == c.IN_HOME) & (ssi > 0) & (income == ssi) + 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) & (ssi == 0) + diversion = max_(person("or_ssp_spousal_diversion_difference", period), 0) + available = max_(person("or_ssp_available_room_board_income", period), 0) + room_board = (category == c.ROOM_BOARD_ABSENCE) | ( + category == c.ROOM_BOARD_INCAPACITY + ) + amount = select( + [ + in_home, + care & couple, + interim | restoring_ssi | restoring_va, + suspended, + category == c.SPOUSAL_DIVERSION, + room_board, + ], + [ + p.in_home_amount, + couple_payment, + max_(standard - income, 0), + max_(p.room_and_board - income, 0), + diversion + max_(standard - income, 0), + max_(p.room_and_board - available, 0), + ], + default=0, + ) + days = clip(person("or_ssp_days_eligible", period), 0, period.days) + # 461-160-0070 uses actual calendar days and does not round the result. + prorated = amount * days / period.days + initial = min_( + max_(person("or_ssp_approved_initial_room_board", period), 0), + p.room_and_board, + ) + return where(category == c.INITIAL_ROOM_BOARD, initial * (days > 0), 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..1a561dcbafb --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_approved_initial_room_board.py @@ -0,0 +1,13 @@ +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://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf", + ) + 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_available_room_board_income.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py new file mode 100644 index 00000000000..22e41192df5 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class or_ssp_available_room_board_income(Variable): + value_type = float + entity = Person + label = "Oregon income available for special room and board payments" + definition_period = MONTH + unit = USD + reference = ( + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf", + ) + documentation = "Override with accessible income remaining after an assessed care liability during a certified absence, or accessible income in an approved incapacity case." + + def formula(person, period, parameters): + return person("or_ssp_countable_income", period) 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..9b4b5b47356 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_category.py @@ -0,0 +1,44 @@ +from policyengine_us.model_api import * + + +class ORSSPCategory(Enum): + NONE = "No approved OSIPM special need" + 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" + + +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://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf", + ) + 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_snap.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_snap.py new file mode 100644 index 00000000000..1a63e84123e --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_snap.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class or_ssp_countable_for_snap(Variable): + value_type = float + entity = Person + label = "Oregon SSP included in SNAP unearned income" + definition_period = MONTH + unit = USD + reference = ( + "https://sharedsystems.dhsoha.state.or.us/DHSForms/Served/de2818.pdf#page=583", + ) + documentation = "The OPEN manual identifies the in-home supplement as a reimbursement that does not affect other program benefits." + + def formula(person, period, parameters): + category = person("or_ssp_category", period) + reimbursement = category == category.possible_values.IN_HOME + return where(reimbursement, 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..5425a520aa3 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_income.py @@ -0,0 +1,25 @@ +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 = ( + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-001-0000.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0030.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0108.pdf", + ) + documentation = "Includes SSI and countable cash income before the general or earnings deductions. Investment interest and dividends are excluded. Override for other state exclusions, inaccessible income, countable loan interest or sources absent from federal SSI inputs." + + def formula(person, period, parameters): + p = parameters(period).gov.ssa.ssi.income.sources + sources = list(p.earned) + list(p.unearned) + income = sum( + max_(person(name, period), 0) + for name in sources + if name not in ("interest_income", "dividend_income") + ) + return income + person("ssi", period) diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_days_eligible.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_days_eligible.py new file mode 100644 index 00000000000..e55c9cacf19 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_days_eligible.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class or_ssp_days_eligible(Variable): + value_type = int + entity = Person + label = "Days eligible for Oregon SSP this month" + definition_period = MONTH + reference = ( + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-160-0070.pdf", + ) + documentation = "Days for which the approved special need is payable. An approved initial room-and-board payment is already the amount for the covered period." + + def formula(person, period, parameters): + return period.days 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..a3ccdd89884 --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_spousal_diversion_difference.py @@ -0,0 +1,13 @@ +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://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf", + ) + 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 41ead044f46..5df7aceec52 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", "ks_sspp", # Kansas benefits "hi_oss", "la_oss", # Louisiana benefits From 45611bd42621cd9bbfa3e10f1d1b4dd66ac53b4f Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 13 Oct 2026 01:03:25 -0400 Subject: [PATCH 2/5] Normalize Oregon SSP parameter and test formatting --- .../household/household_state_benefits.yaml | 1 + .../hud/annual_income/sources/unearned.yaml | 1 + .../states/or/odhs/ssp/in_home_amount.yaml | 12 +- .../or/odhs/ssp/reduced_va_pension.yaml | 12 +- .../states/or/odhs/ssp/room_and_board.yaml | 9 +- .../gov/states/or/odhs/ssp/integration.yaml | 76 ++++------- .../gov/states/or/odhs/ssp/or_ssp.yaml | 123 +++++++++++------- 7 files changed, 120 insertions(+), 114 deletions(-) diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index e71f09c9312..59dda1fdff8 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -405,6 +405,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 9af17388584..df27995c102 100644 --- a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml @@ -30,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/in_home_amount.yaml b/policyengine_us/parameters/gov/states/or/odhs/ssp/in_home_amount.yaml index 8f4b0388b39..615e9249f1f 100644 --- 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 @@ -1,11 +1,11 @@ -description: Oregon provides this monthly reimbursement to SSI-only recipients with authorized in-home - care. +description: Oregon provides this monthly reimbursement to SSI-only recipients with authorized in-home care. values: - '2016-01-01': 22 + 2016-01-01: 22 + metadata: unit: currency-USD + period: month label: Oregon SSP in-home reimbursement reference: - - title: OAR 461-155-0575 - href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf - period: month + - title: OAR 461-155-0575 + href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf 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 index 53e5fafa002..4afd70fbc68 100644 --- 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 @@ -1,11 +1,11 @@ -description: Oregon permits the restoration supplement for recipients leaving a nursing facility with - a Veterans benefit no larger than this amount. +description: Oregon permits the restoration supplement for recipients leaving a nursing facility with a Veterans benefit no larger than this amount. values: - '2024-10-01': 90 + 2024-10-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://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf - period: month + - title: OAR 461-155-0700(1)(b) + href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf 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 index 6a7ccbedbb8..27b83c4818c 100644 --- 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 @@ -1,10 +1,11 @@ description: Oregon uses this monthly room and board standard for OSIPM special needs payments. values: - '2026-01-01': 773 + 2026-01-01: 773 + metadata: unit: currency-USD + period: month label: Oregon OSIPM room and board standard reference: - - title: OEP-PT-25-045, January 2026 standards - href: https://www.oregon.gov/odhs/transmittals/oeptransmittals/pt25045.pdf - period: month + - title: OEP-PT-25-045, January 2026 standards + href: https://www.oregon.gov/odhs/transmittals/oeptransmittals/pt25045.pdf 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 index 23b8a59cf11..93f18e313dd 100644 --- 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 @@ -3,112 +3,92 @@ absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 or_ssp_category: COMMUNITY_CARE - second: + person2: age: 65 or_ssp_category: COMMUNITY_CARE marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: OR output: - or_ssp: - - 248.5 - - 248.5 + 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: - first: + person1: age: 65 or_ssp_category: COMMUNITY_CARE ssi: 700 - or_ssp_countable_income: 1100 - second: + or_ssp_countable_income: 1_100 + person2: age: 65 or_ssp_category: COMMUNITY_CARE ssi: 700 or_ssp_countable_income: 700 marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: OR output: - or_ssp: - - 0 - - 188 + or_ssp: [0, 188] + - name: Case 3, both spouses must receive SSI. period: 2026-01 absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 or_ssp_category: COMMUNITY_CARE - second: + person2: age: 65 or_ssp_category: COMMUNITY_CARE ssi: 0 marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: OR output: - or_ssp: - - 0 - - 0 + or_ssp: [0, 0] + - name: Case 4, both spouses must have community care. period: 2026-01 absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 or_ssp_category: COMMUNITY_CARE - second: + person2: age: 65 or_ssp_category: NONE marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: OR output: - or_ssp: - - 0 - - 0 + or_ssp: [0, 0] + - name: Case 5, in-home reimbursement excluded from SNAP income. - period: '2026' + period: 2026 absolute_error_margin: 0.01 input: age: 65 @@ -116,5 +96,5 @@ or_ssp_category: IN_HOME output: or_ssp: 264 - snap_unearned_income: 11928 - hud_unearned_income: 11928 + snap_unearned_income: 11_928 + hud_unearned_income: 11_928 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 index 8945959511d..9fa8a1854ed 100644 --- 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 @@ -3,286 +3,309 @@ absolute_error_margin: 0.01 input: state_code: - '2026': OR + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: IN_HOME output: or_ssp: 22 + - name: Case 3, ten dollars other cash income disqualifies before deductions. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': OR + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: IN_HOME social_security_retirement: 120 output: or_ssp: 0 + - name: Case 4, small earnings disqualify before deductions. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': OR + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: IN_HOME employment_income: 120 output: 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 + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: 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 + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: DISABILITY_INTERIM ssi: 0 - employment_income: 1200 + 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 + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: VA_RESTORATION ssi: 0 - veterans_benefits: 1080 + 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 + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: SSI_RESTORATION ssi: 30 or_ssp_days_eligible: 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 + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: DISABILITY_INTERIM ssi: 0 or_ssp_days_eligible: 14 output: or_ssp: 497 + - name: Case 17, zero eligible days. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': OR + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: IN_HOME or_ssp_days_eligible: 0 output: or_ssp: 0 + - name: Case 18, spousal diversion includes income shortfall. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': OR + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: SPOUSAL_DIVERSION ssi: 0 - social_security_retirement: 9600 + 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 + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: SPOUSAL_DIVERSION ssi: 0 - social_security_retirement: 14400 + 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 + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: ROOM_BOARD_ABSENCE or_ssp_available_room_board_income: 200 output: or_ssp: 573 + - name: Case 21, incapacity payment uses accessible income. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': OR + 2026: OR age: - '2026': 65 + 2026: 65 or_ssp_category: ROOM_BOARD_INCAPACITY or_ssp_available_room_board_income: 0 output: 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 + 2026: OR age: - '2026': 65 + 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 + 2026: OR age: - '2026': 65 + 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: WA age: - '2026': 65 + 2026: 65 or_ssp_category: IN_HOME output: or_ssp: 0 From 0fdaef588fe5675bb5e9df2e2a07382026c88c7b Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 13 Oct 2026 02:42:42 -0400 Subject: [PATCH 3/5] Fix issues from review: Oregon SSP code-health, income-list helper and tests - Replace builtin sum() over entity calls with a loop; move excluded sources to a parameter - One program-neutral helper (payment excluding the in-home supplement) for SNAP and HUD, with its own references - Revert shared SNAP comment and HUD metadata edits; registry placement and comments; SNAP title; programs.yaml note - Accept reported SSI receipt for the in-home supplement; keep it out of the suspended-SSI category - Governing OAR citations and page anchors - Realistic couple integration case; SNAP/HUD flow, available-income and reported-receipt cases Co-Authored-By: Claude Opus 5.5 --- .../household/household_state_benefits.yaml | 12 ++-- .../hud/annual_income/sources/unearned.yaml | 4 +- .../or/odhs/ssp/excluded_income_sources.yaml | 15 ++++ .../states/or/odhs/ssp/in_home_amount.yaml | 2 +- .../or/odhs/ssp/reduced_va_pension.yaml | 2 +- .../states/or/odhs/ssp/room_and_board.yaml | 4 +- .../usda/snap/income/sources/unearned.yaml | 10 +-- policyengine_us/programs.yaml | 10 ++- .../gov/states/or/odhs/ssp/integration.yaml | 68 +++++++++++++++++-- .../gov/states/or/odhs/ssp/or_ssp.yaml | 52 ++++++++++++-- .../gov/states/or/odhs/ssp/or_ssp.py | 16 +++-- .../ssp/or_ssp_approved_initial_room_board.py | 2 +- .../ssp/or_ssp_available_room_board_income.py | 3 +- .../gov/states/or/odhs/ssp/or_ssp_category.py | 8 ++- .../or/odhs/ssp/or_ssp_countable_for_snap.py | 18 ----- .../or/odhs/ssp/or_ssp_countable_income.py | 23 ++++--- .../or_ssp_excluding_in_home_supplement.py | 27 ++++++++ .../or_ssp_spousal_diversion_difference.py | 2 +- .../income/spm_unit/spm_unit_benefits.py | 2 +- 19 files changed, 209 insertions(+), 71 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/or/odhs/ssp/excluded_income_sources.yaml delete mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_snap.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_excluding_in_home_supplement.py diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index 59dda1fdff8..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 @@ -78,7 +80,6 @@ values: # DC benefits - dc_ossp # Kansas benefits - - or_ssp - ks_sspp # Hawaii benefits - hi_oss @@ -158,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 @@ -177,7 +180,6 @@ values: # DC benefits - dc_ossp # Kansas benefits - - or_ssp - ks_sspp # Hawaii benefits - hi_oss @@ -261,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 @@ -281,7 +285,6 @@ values: - dc_ossp - dc_child_care_subsidies # Kansas benefits - - or_ssp - ks_sspp # Hawaii benefits - hi_oss @@ -365,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 @@ -385,7 +390,6 @@ values: - dc_ossp - dc_child_care_subsidies # Kansas benefits - - or_ssp - ks_sspp # Hawaii benefits - hi_oss 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 df27995c102..0aee65abcc1 100644 --- a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml @@ -19,7 +19,7 @@ values: - strike_benefits - social_security - ssi - - or_ssp_countable_for_snap + - or_ssp_excluding_in_home_supplement - general_assistance - unemployment_compensation - child_support_received @@ -36,5 +36,5 @@ metadata: period: year label: HUD unearned income sources reference: - - title: 24 CFR § 5.609(a)(1), (a)(2), (b)(6), (b)(19) + - title: 24 CFR § 5.609(a)(1), (a)(2) href: https://www.law.cornell.edu/cfr/text/24/5.609 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..ddc8b78c1e1 --- /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://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0030.pdf#page=2 + - title: OAR 461-145-0108(1)(a) + href: https://odhsssprulesprdwu1st01.blob.core.windows.net/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 index 615e9249f1f..a0e39f83e7b 100644 --- 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 @@ -7,5 +7,5 @@ metadata: period: month label: Oregon SSP in-home reimbursement reference: - - title: OAR 461-155-0575 + - title: OAR 461-155-0575(2) href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf 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 index 4afd70fbc68..252e3428bda 100644 --- 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 @@ -8,4 +8,4 @@ metadata: label: Oregon SSP reduced VA pension limit reference: - title: OAR 461-155-0700(1)(b) - href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf + href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf#page=1 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 index 27b83c4818c..10bf92734ef 100644 --- 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 @@ -7,5 +7,7 @@ metadata: period: month label: Oregon OSIPM room and board standard reference: + - title: OAR 461-155-0270 + href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0270.pdf - title: OEP-PT-25-045, January 2026 standards - href: https://www.oregon.gov/odhs/transmittals/oeptransmittals/pt25045.pdf + 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 66d112647e9..1c11505aa7d 100644 --- a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml @@ -16,9 +16,9 @@ values: # exempts public assistance vendor payments only for medical assistance, # child care, energy assistance, migrant emergency assistance, housing # authority housing assistance, and emergency or special assistance that - # is not the normal grant. Countable components below exclude medical - # reimbursements and state-specific exempt payments; ordinary cash and - # room-and-board supplements count even when paid to a provider. + # is not the normal grant. None of the supplements below fall in those + # categories, so each counts, whether paid to the recipient or to a + # facility on the recipient's behalf. - ak_ssp - al_ssp # co_oap has an annual definition period; policyengine-core's @@ -36,7 +36,6 @@ values: - hi_oss - id_aabd - in_ssp - - or_ssp_countable_for_snap - ks_sspp - ky_ssp - la_oss @@ -48,6 +47,7 @@ values: - mo_ssp - ne_aabd - nm_ssi_state_supplement + - or_ssp_excluding_in_home_supplement - sc_ssi_state_supplement - tx_ssi_state_supplement - wa_ssp @@ -96,7 +96,7 @@ values: metadata: reference: - - title: 7 CFR 273.9(b)(2) and (c)(1), (5) + - 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 7155d40381c..898bb5ffec0 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1096,12 +1096,10 @@ programs: full_name: Oregon State Supplemental Payment variable: or_ssp parameter_prefix: gov.states.or.odhs.ssp - verified_years: '2026' - notes: OSIPM in-home, SSI couple community care, transitional personal incidentals/room - and board, and approved spousal diversion and special room-and-board payments. Eligibility - and procedural authorization require a certified category; specialized income exclusions, - liability and diversion need explicit inputs. Other medical reimbursements and historical - mandatory supplements are excluded. + verified_years: "2026" + notes: Models 2026 OSIPM in-home, SSI couple community care, transitional personal + incidentals/room and board, spousal diversion and special room-and-board 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 index 93f18e313dd..65b40123580 100644 --- 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 @@ -27,13 +27,11 @@ person1: age: 65 or_ssp_category: COMMUNITY_CARE - ssi: 700 - or_ssp_countable_income: 1_100 + # $1,200 a month. + social_security_retirement: 14_400 person2: age: 65 or_ssp_category: COMMUNITY_CARE - ssi: 700 - or_ssp_countable_income: 700 marital_units: couple: members: [person1, person2] @@ -42,7 +40,15 @@ members: [person1, person2] state_code: OR output: - or_ssp: [0, 188] + # 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 @@ -98,3 +104,55 @@ or_ssp: 264 snap_unearned_income: 11_928 hud_unearned_income: 11_928 + +- name: Case 6, community care payment counts as SNAP and HUD 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 the full payment counts. + or_ssp_excluding_in_home_supplement: [0, 5_724] + # 12 * (1,200 Social Security + 311 SSI + 477 SSP) = 12 * 1,988 = 23,856. + snap_unearned_income: 23_856 + # 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 counts all countable income as available by default. + 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 liability override, so available income equals countable income. + or_ssp_available_room_board_income: 1_014 + # 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 index 9fa8a1854ed..41360527fd1 100644 --- 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 @@ -21,7 +21,7 @@ output: or_ssp: 22 -- name: Case 3, ten dollars other cash income disqualifies before deductions. +- name: Case 3, Social Security income disqualifies the in-home supplement. period: 2026-01 absolute_error_margin: 0.01 input: @@ -30,11 +30,14 @@ age: 2026: 65 or_ssp_category: IN_HOME - social_security_retirement: 120 + # $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, small earnings disqualify before deductions. +- name: Case 4, part-time earnings disqualify the in-home supplement. period: 2026-01 absolute_error_margin: 0.01 input: @@ -43,8 +46,12 @@ age: 2026: 65 or_ssp_category: IN_HOME - employment_income: 120 + # 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. @@ -79,7 +86,8 @@ input: state_code: 2026: OR - age: 40 + age: + 2026: 40 or_ssp_category: DISABILITY_INTERIM ssi: 0 output: @@ -303,9 +311,41 @@ period: 2026-01 absolute_error_margin: 0.01 input: - state_code: WA + 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 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 index 6a49c1d1322..584446a0386 100644 --- a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py @@ -8,9 +8,12 @@ class or_ssp(Variable): definition_period = MONTH unit = USD reference = ( + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0250.pdf#page=1", "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf", + # PDF pages 1-3 + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf#page=1", + # PDF pages 1-3 + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf#page=1", "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-160-0070.pdf", ) defined_for = StateCode.OR @@ -18,12 +21,17 @@ class or_ssp(Variable): 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) - in_home = (category == c.IN_HOME) & (ssi > 0) & (income == ssi) + 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) @@ -41,7 +49,7 @@ def formula(person, period, parameters): & (veterans > 0) & (veterans <= p.reduced_va_pension) ) - suspended = (category == c.SUSPENDED_SSI) & (ssi == 0) + suspended = (category == c.SUSPENDED_SSI) & ~receives_ssi diversion = max_(person("or_ssp_spousal_diversion_difference", period), 0) available = max_(person("or_ssp_available_room_board_income", period), 0) room_board = (category == c.ROOM_BOARD_ABSENCE) | ( 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 index 1a561dcbafb..e925c6984c4 100644 --- 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 @@ -8,6 +8,6 @@ class or_ssp_approved_initial_room_board(Variable): definition_period = MONTH unit = USD reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/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_available_room_board_income.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py index 22e41192df5..88dfafbfe63 100644 --- a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py @@ -8,7 +8,8 @@ class or_ssp_available_room_board_income(Variable): definition_period = MONTH unit = USD reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf", + # PDF pages 1-3 + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf#page=1", ) documentation = "Override with accessible income remaining after an assessed care liability during a certified absence, or accessible income in an approved incapacity case." 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 index 9b4b5b47356..b0d566a5453 100644 --- 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 @@ -2,7 +2,6 @@ class ORSSPCategory(Enum): - NONE = "No approved OSIPM special need" IN_HOME = "Approved SSI-only in-home services" COMMUNITY_CARE = "Approved licensed community care with an SSI spouse" DISABILITY_INTERIM = ( @@ -20,6 +19,7 @@ class ORSSPCategory(Enum): "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): @@ -31,8 +31,10 @@ class or_ssp_category(Variable): default_value = ORSSPCategory.NONE reference = ( "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf", + # PDF pages 1-3 + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf#page=1", + # PDF pages 1-3 + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf#page=1", ) documentation = """ Select only after OSIPM financial eligibility, placement/service authorization, diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_snap.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_snap.py deleted file mode 100644 index 1a63e84123e..00000000000 --- a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_snap.py +++ /dev/null @@ -1,18 +0,0 @@ -from policyengine_us.model_api import * - - -class or_ssp_countable_for_snap(Variable): - value_type = float - entity = Person - label = "Oregon SSP included in SNAP unearned income" - definition_period = MONTH - unit = USD - reference = ( - "https://sharedsystems.dhsoha.state.or.us/DHSForms/Served/de2818.pdf#page=583", - ) - documentation = "The OPEN manual identifies the in-home supplement as a reimbursement that does not affect other program benefits." - - def formula(person, period, parameters): - category = person("or_ssp_category", period) - reimbursement = category == category.possible_values.IN_HOME - return where(reimbursement, 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 index 5425a520aa3..11da42e36ba 100644 --- 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 @@ -8,18 +8,19 @@ class or_ssp_countable_income(Variable): definition_period = MONTH unit = USD reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-001-0000.pdf", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0030.pdf", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0108.pdf", + # PDF pages 1, 5 + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-001-0000.pdf#page=1", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0030.pdf#page=2", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0108.pdf#page=1", ) documentation = "Includes SSI and countable cash income before the general or earnings deductions. Investment interest and dividends are excluded. Override for other state exclusions, inaccessible income, countable loan interest or sources absent from federal SSI inputs." def formula(person, period, parameters): - p = parameters(period).gov.ssa.ssi.income.sources - sources = list(p.earned) + list(p.unearned) - income = sum( - max_(person(name, period), 0) - for name in sources - if name not in ("interest_income", "dividend_income") - ) - return income + person("ssi", period) + 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) + return income diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_excluding_in_home_supplement.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_excluding_in_home_supplement.py new file mode 100644 index 00000000000..9fac259cdce --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_excluding_in_home_supplement.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class or_ssp_excluding_in_home_supplement(Variable): + value_type = float + entity = Person + label = "Oregon SSP excluding the in-home supplement" + definition_period = MONTH + unit = USD + reference = ( + "https://www.law.cornell.edu/cfr/text/7/273.9#c_5", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0410.pdf#page=2", + # 24 CFR 5.609(b)(6), (b)(19) + "https://www.law.cornell.edu/cfr/text/24/5.609", + "https://sharedsystems.dhsoha.state.or.us/DHSForms/Served/de2818.pdf#page=583", + ) + defined_for = StateCode.OR + documentation = "The Oregon SSP payment excluding the in-home supplement, which is a reimbursement for uncovered assistance needs. SNAP and HUD count this amount as unearned income." + + def formula(person, period, parameters): + # NOTE: OAR 461-145-0410(7)(c)(D) excludes most special needs payments + # from SNAP income as reimbursements. The model follows 7 CFR + # 273.9(c)(5), which counts payments for normal living expenses such + # as room and board, and excludes only the in-home supplement. + 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_spousal_diversion_difference.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_spousal_diversion_difference.py index a3ccdd89884..f5cc59e0a86 100644 --- 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 @@ -8,6 +8,6 @@ class or_ssp_spousal_diversion_difference(Variable): definition_period = MONTH unit = USD reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf", + "https://odhsssprulesprdwu1st01.blob.core.windows.net/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 5df7aceec52..8e165b5536c 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,7 +22,7 @@ def formula(spm_unit, period, parameters): "ky_ssp", # Kentucky benefits "de_ssp", # Delaware benefits "fl_oss", - "or_ssp", + "or_ssp", # Oregon benefits "ks_sspp", # Kansas benefits "hi_oss", "la_oss", # Louisiana benefits From badb1c96c5a45a64ad5d4fdd1375f1f44dd88fa6 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 15 Oct 2026 16:45:39 -0400 Subject: [PATCH 4/5] Address review: Oregon SSP nursing facility payment, SNAP and inputs - Model the OAR 461-155-0250(4)(c) nursing facility payment. - Stop counting the special-need payments as SNAP income (OAR 461-145-0410(7)(c)(D)); keep them in HUD as or_ssp_countable_for_hud. - Replace the partial-month days and available room-and-board income formula inputs with zero-default inputs (partial-month days, care liability, inaccessible income), so entering one for one person leaves others unchanged. - Update descriptions, references (ch461rules host, ORS 411) and the reduced VA pension date, and add tests. Co-Authored-By: Claude Opus 5.5 --- .../hud/annual_income/sources/unearned.yaml | 2 +- .../or/odhs/ssp/excluded_income_sources.yaml | 4 +- .../states/or/odhs/ssp/in_home_amount.yaml | 4 +- .../nursing_facility_payment_standard.yaml | 18 ++ .../or/odhs/ssp/reduced_va_pension.yaml | 8 +- .../states/or/odhs/ssp/room_and_board.yaml | 4 +- .../usda/snap/income/sources/unearned.yaml | 5 +- policyengine_us/programs.yaml | 5 +- .../gov/states/or/odhs/ssp/integration.yaml | 22 +- .../gov/states/or/odhs/ssp/or_ssp.yaml | 193 +++++++++++++++++- .../gov/states/or/odhs/ssp/or_ssp.py | 55 +++-- .../ssp/or_ssp_approved_initial_room_board.py | 4 +- .../ssp/or_ssp_available_room_board_income.py | 17 -- .../or/odhs/ssp/or_ssp_care_liability.py | 16 ++ .../gov/states/or/odhs/ssp/or_ssp_category.py | 6 +- .../or/odhs/ssp/or_ssp_countable_for_hud.py | 22 ++ .../or/odhs/ssp/or_ssp_countable_income.py | 14 +- .../or/odhs/ssp/or_ssp_days_eligible.py | 15 -- .../or_ssp_excluding_in_home_supplement.py | 27 --- .../or/odhs/ssp/or_ssp_inaccessible_income.py | 16 ++ .../or/odhs/ssp/or_ssp_partial_month_days.py | 14 ++ .../or_ssp_spousal_diversion_difference.py | 4 +- 22 files changed, 353 insertions(+), 122 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/or/odhs/ssp/nursing_facility_payment_standard.yaml delete mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_care_liability.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_countable_for_hud.py delete mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_days_eligible.py delete mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_excluding_in_home_supplement.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_inaccessible_income.py create mode 100644 policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_partial_month_days.py 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 0aee65abcc1..a85058a7ac5 100644 --- a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml @@ -19,7 +19,7 @@ values: - strike_benefits - social_security - ssi - - or_ssp_excluding_in_home_supplement + - or_ssp_countable_for_hud - general_assistance - unemployment_compensation - child_support_received 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 index ddc8b78c1e1..31ec0e3b287 100644 --- 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 @@ -10,6 +10,6 @@ metadata: label: Oregon SSP excluded income sources reference: - title: OAR 461-145-0030(4) - href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0030.pdf#page=2 + href: https://ch461rules.odhs.oregon.gov/rules/461-145-0030.pdf#page=2 - title: OAR 461-145-0108(1)(a) - href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0108.pdf#page=1 + 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 index a0e39f83e7b..894ded26f79 100644 --- 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 @@ -1,4 +1,4 @@ -description: Oregon provides this monthly reimbursement to SSI-only recipients with authorized in-home care. +description: Oregon provides this amount as the monthly in-home supplement under the State Supplemental Payment program. values: 2016-01-01: 22 @@ -8,4 +8,4 @@ metadata: label: Oregon SSP in-home reimbursement reference: - title: OAR 461-155-0575(2) - href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf + 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 index 252e3428bda..1c0cbc05ec2 100644 --- 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 @@ -1,6 +1,6 @@ -description: Oregon permits the restoration supplement for recipients leaving a nursing facility with a Veterans benefit no larger than this amount. +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: - 2024-10-01: 90 + 2020-01-01: 90 metadata: unit: currency-USD @@ -8,4 +8,6 @@ metadata: label: Oregon SSP reduced VA pension limit reference: - title: OAR 461-155-0700(1)(b) - href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf#page=1 + 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 index 10bf92734ef..b4a84ab0e54 100644 --- 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 @@ -1,4 +1,4 @@ -description: Oregon uses this monthly room and board standard for OSIPM special needs payments. +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 @@ -8,6 +8,6 @@ metadata: label: Oregon OSIPM room and board standard reference: - title: OAR 461-155-0270 - href: https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0270.pdf + 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 1c11505aa7d..768207ecab8 100644 --- a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml @@ -47,10 +47,13 @@ values: - mo_ssp - ne_aabd - nm_ssi_state_supplement - - or_ssp_excluding_in_home_supplement - 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 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 898bb5ffec0..5ebd553a506 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1098,8 +1098,9 @@ programs: 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 and special room-and-board payments. - Other special needs and historical mandatory supplements are not modeled. + 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 index 65b40123580..344bb1f05ec 100644 --- 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 @@ -61,7 +61,7 @@ person2: age: 65 or_ssp_category: COMMUNITY_CARE - ssi: 0 + takes_up_ssi_if_eligible: false marital_units: couple: members: [person1, person2] @@ -70,6 +70,7 @@ 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. @@ -93,7 +94,7 @@ output: or_ssp: [0, 0] -- name: Case 5, in-home reimbursement excluded from SNAP income. +- name: Case 5, in-home reimbursement excluded from SNAP and HUD income. period: 2026 absolute_error_margin: 0.01 input: @@ -102,10 +103,11 @@ 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 SNAP and HUD unearned income. +- name: Case 6, community care payment counts as HUD but not SNAP unearned income. period: 2026 absolute_error_margin: 0.01 input: @@ -130,15 +132,16 @@ ssi: [1_866, 1_866] # person2: 477 * 12 = 5,724. or_ssp: [0, 5_724] - # Community care is not the in-home reimbursement, so the full payment counts. - or_ssp_excluding_in_home_supplement: [0, 5_724] - # 12 * (1,200 Social Security + 311 SSI + 477 SSP) = 12 * 1,988 = 23,856. - snap_unearned_income: 23_856 + # 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 counts all countable income as available by default. +- name: Case 7, temporary absence without a care liability counts all countable income. period: 2026-01 absolute_error_margin: 0.01 input: @@ -152,7 +155,6 @@ ssi: 514 # 514 SSI + 500 Social Security = 1,014. or_ssp_countable_income: 1_014 - # No liability override, so available income equals countable income. - or_ssp_available_room_board_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 index 41360527fd1..1718c440bf8 100644 --- 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 @@ -100,7 +100,7 @@ state_code: 2026: OR age: - 2026: 65 + 2026: 40 or_ssp_category: DISABILITY_INTERIM ssi: 0 employment_income: 1_200 @@ -194,7 +194,7 @@ 2026: 65 or_ssp_category: SSI_RESTORATION ssi: 30 - or_ssp_days_eligible: 16 + or_ssp_partial_month_days: 16 output: or_ssp: 497.5483870967742 @@ -205,14 +205,14 @@ state_code: 2026: OR age: - 2026: 65 + 2026: 40 or_ssp_category: DISABILITY_INTERIM ssi: 0 - or_ssp_days_eligible: 14 + or_ssp_partial_month_days: 14 output: or_ssp: 497 -- name: Case 17, zero eligible days. +- name: Case 17, eligible days covering the whole month pay the full amount. period: 2026-01 absolute_error_margin: 0.01 input: @@ -221,9 +221,9 @@ age: 2026: 65 or_ssp_category: IN_HOME - or_ssp_days_eligible: 0 + or_ssp_partial_month_days: 31 output: - or_ssp: 0 + or_ssp: 22 - name: Case 18, spousal diversion includes income shortfall. period: 2026-01 @@ -264,9 +264,14 @@ age: 2026: 65 or_ssp_category: ROOM_BOARD_ABSENCE - or_ssp_available_room_board_income: 200 + # $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: - or_ssp: 573 + # 773 - (1,200 - 1,118.72) = 691.72. + or_ssp: 691.72 - name: Case 21, incapacity payment uses accessible income. period: 2026-01 @@ -277,8 +282,12 @@ age: 2026: 65 or_ssp_category: ROOM_BOARD_INCAPACITY - or_ssp_available_room_board_income: 0 + # $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. @@ -349,3 +358,167 @@ # 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] 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 index 584446a0386..80da0a570b1 100644 --- a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp.py @@ -8,13 +8,20 @@ class or_ssp(Variable): definition_period = MONTH unit = USD reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0250.pdf#page=1", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf", + # 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://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf#page=1", + "https://ch461rules.odhs.oregon.gov/rules/461-155-0630.pdf#page=1", # PDF pages 1-3 - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf#page=1", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-160-0070.pdf", + "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 @@ -51,34 +58,50 @@ def formula(person, period, parameters): ) suspended = (category == c.SUSPENDED_SSI) & ~receives_ssi diversion = max_(person("or_ssp_spousal_diversion_difference", period), 0) - available = max_(person("or_ssp_available_room_board_income", period), 0) - room_board = (category == c.ROOM_BOARD_ABSENCE) | ( - category == c.ROOM_BOARD_INCAPACITY - ) + 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, + suspended | absence | incapacity, category == c.SPOUSAL_DIVERSION, - room_board, + nursing_facility, ], [ p.in_home_amount, couple_payment, max_(standard - income, 0), - max_(p.room_and_board - income, 0), + max_(p.room_and_board - room_board_income, 0), diversion + max_(standard - income, 0), - max_(p.room_and_board - available, 0), + max_(p.nursing_facility_payment_standard - income, 0), ], default=0, ) - days = clip(person("or_ssp_days_eligible", period), 0, period.days) + 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 = amount * days / period.days + 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 * (days > 0), prorated) + 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 index e925c6984c4..ce881a5ad7d 100644 --- 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 @@ -7,7 +7,5 @@ class or_ssp_approved_initial_room_board(Variable): label = "Oregon approved initial placement room and board payment" definition_period = MONTH unit = USD - reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf#page=1", - ) + 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_available_room_board_income.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py deleted file mode 100644 index 88dfafbfe63..00000000000 --- a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_available_room_board_income.py +++ /dev/null @@ -1,17 +0,0 @@ -from policyengine_us.model_api import * - - -class or_ssp_available_room_board_income(Variable): - value_type = float - entity = Person - label = "Oregon income available for special room and board payments" - definition_period = MONTH - unit = USD - reference = ( - # PDF pages 1-3 - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf#page=1", - ) - documentation = "Override with accessible income remaining after an assessed care liability during a certified absence, or accessible income in an approved incapacity case." - - def formula(person, period, parameters): - return person("or_ssp_countable_income", period) 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 index b0d566a5453..609ce24a42a 100644 --- 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 @@ -30,11 +30,11 @@ class or_ssp_category(Variable): possible_values = ORSSPCategory default_value = ORSSPCategory.NONE reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0575.pdf", + "https://ch461rules.odhs.oregon.gov/rules/461-155-0575.pdf", # PDF pages 1-3 - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0630.pdf#page=1", + "https://ch461rules.odhs.oregon.gov/rules/461-155-0630.pdf#page=1", # PDF pages 1-3 - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf#page=1", + "https://ch461rules.odhs.oregon.gov/rules/461-155-0700.pdf#page=1", ) documentation = """ Select only after OSIPM financial eligibility, placement/service authorization, 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 index 11da42e36ba..d1350188688 100644 --- 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 @@ -9,11 +9,12 @@ class or_ssp_countable_income(Variable): unit = USD reference = ( # PDF pages 1, 5 - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-001-0000.pdf#page=1", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0030.pdf#page=2", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0108.pdf#page=1", + "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 are excluded. Override for other state exclusions, inaccessible income, countable loan interest or sources absent from federal SSI inputs." + 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 @@ -23,4 +24,7 @@ def formula(person, period, parameters): for name in list(sources.earned) + list(sources.unearned): if name not in excluded: income = income + max_(person(name, period), 0) - return income + # 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_days_eligible.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_days_eligible.py deleted file mode 100644 index e55c9cacf19..00000000000 --- a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_days_eligible.py +++ /dev/null @@ -1,15 +0,0 @@ -from policyengine_us.model_api import * - - -class or_ssp_days_eligible(Variable): - value_type = int - entity = Person - label = "Days eligible for Oregon SSP this month" - definition_period = MONTH - reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-160-0070.pdf", - ) - documentation = "Days for which the approved special need is payable. An approved initial room-and-board payment is already the amount for the covered period." - - def formula(person, period, parameters): - return period.days diff --git a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_excluding_in_home_supplement.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_excluding_in_home_supplement.py deleted file mode 100644 index 9fac259cdce..00000000000 --- a/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_excluding_in_home_supplement.py +++ /dev/null @@ -1,27 +0,0 @@ -from policyengine_us.model_api import * - - -class or_ssp_excluding_in_home_supplement(Variable): - value_type = float - entity = Person - label = "Oregon SSP excluding the in-home supplement" - definition_period = MONTH - unit = USD - reference = ( - "https://www.law.cornell.edu/cfr/text/7/273.9#c_5", - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-145-0410.pdf#page=2", - # 24 CFR 5.609(b)(6), (b)(19) - "https://www.law.cornell.edu/cfr/text/24/5.609", - "https://sharedsystems.dhsoha.state.or.us/DHSForms/Served/de2818.pdf#page=583", - ) - defined_for = StateCode.OR - documentation = "The Oregon SSP payment excluding the in-home supplement, which is a reimbursement for uncovered assistance needs. SNAP and HUD count this amount as unearned income." - - def formula(person, period, parameters): - # NOTE: OAR 461-145-0410(7)(c)(D) excludes most special needs payments - # from SNAP income as reimbursements. The model follows 7 CFR - # 273.9(c)(5), which counts payments for normal living expenses such - # as room and board, and excludes only the in-home supplement. - 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_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..fbb54cee90f --- /dev/null +++ b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_partial_month_days.py @@ -0,0 +1,14 @@ +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." 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 index f5cc59e0a86..17be97ab0df 100644 --- 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 @@ -7,7 +7,5 @@ class or_ssp_spousal_diversion_difference(Variable): label = "Oregon additional diversion available under nursing facility placement" definition_period = MONTH unit = USD - reference = ( - "https://odhsssprulesprdwu1st01.blob.core.windows.net/rules/461-155-0700.pdf#page=2", - ) + 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)." From 3311c3b18f300ec5fde4e323a449215ad8bbe232 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 15 Oct 2026 18:39:38 -0400 Subject: [PATCH 5/5] Stop Oregon SSP partial-month days from carrying into later months A formula-less monthly input carries forward to later months, so a partial month also prorated every month after it. A formula that returns 0 keeps a one-month entry to that month. Co-Authored-By: Claude Opus 5.5 --- .../gov/states/or/odhs/ssp/or_ssp.yaml | 18 ++++++++++++++++++ .../or/odhs/ssp/or_ssp_partial_month_days.py | 4 ++++ 2 files changed, 22 insertions(+) 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 index 1718c440bf8..0aeb7eef1f5 100644 --- 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 @@ -522,3 +522,21 @@ # 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_partial_month_days.py b/policyengine_us/variables/gov/states/or/odhs/ssp/or_ssp_partial_month_days.py index fbb54cee90f..9c7c3ddfb31 100644 --- 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 @@ -12,3 +12,7 @@ class or_ssp_partial_month_days(Variable): "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