From 7c38911c55712275a07cff80c2699444bd454f98 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 16 Apr 2026 12:59:17 -0400 Subject: [PATCH 01/23] Initialize Iowa SSP branch --- changelog.d/ia-ssp.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/ia-ssp.added.md diff --git a/changelog.d/ia-ssp.added.md b/changelog.d/ia-ssp.added.md new file mode 100644 index 00000000000..1f2ad14cdf9 --- /dev/null +++ b/changelog.d/ia-ssp.added.md @@ -0,0 +1 @@ +Added Iowa State Supplementary Payment (SSP). From 1c921b458f902cf32b5690d41eaf627b12105e9f Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 16 Apr 2026 14:33:14 -0400 Subject: [PATCH 02/23] Implement Iowa State Supplementary Assistance (SSA) Adds Iowa SSA (Iowa Code Ch 249; IAC 441 Chs 50-52, 54, 177) covering: - Blind supplement (flat $22/month) - Dependent Person (DP) supplement (5 household configurations) - Family-Life Home (FLH) supplement (max $142/month) - In-Home Health-Related Care (IHHRC) supplement (cost-based, max $480.55/$961.10) - Residential Care Facility (RCF) supplement (cost-related per diem) - Supplement for Medicare and Medicaid Eligibles (SMME) (flat $1/month) Closes #7733 --- changelog.d/ia-ssp.added.md | 2 +- .../household/household_state_benefits.yaml | 4 + .../gov/states/ia/hhs/ssa/blind.yaml | 14 ++ .../ia/hhs/ssa/dp/assistance_standard.yaml | 32 +++++ .../ia/hhs/ssa/dp/dependent_income_limit.yaml | 15 ++ .../ia/hhs/ssa/dp/max_per_person_cap.yaml | 15 ++ .../ia/hhs/ssa/flh/assistance_standard.yaml | 15 ++ .../states/ia/hhs/ssa/flh/max_supplement.yaml | 14 ++ .../hhs/ssa/flh/personal_needs_allowance.yaml | 15 ++ .../ia/hhs/ssa/ihhrc/max_cost_couple.yaml | 14 ++ .../ia/hhs/ssa/ihhrc/max_cost_single.yaml | 14 ++ .../ia/hhs/ssa/rcf/days_multiplier.yaml | 14 ++ .../states/ia/hhs/ssa/rcf/max_per_diem.yaml | 15 ++ .../hhs/ssa/rcf/personal_needs_allowance.yaml | 17 +++ .../gov/states/ia/hhs/ssa/smme.yaml | 14 ++ .../ia/hhs/ssa/ia_ssa_blind_supplement.yaml | 67 +++++++++ .../ia/hhs/ssa/ia_ssa_dp_configuration.yaml | 77 ++++++++++ .../ia/hhs/ssa/ia_ssa_dp_supplement.yaml | 91 ++++++++++++ .../states/ia/hhs/ssa/ia_ssa_eligible.yaml | 63 +++++++++ .../ia/hhs/ssa/ia_ssa_flh_supplement.yaml | 70 ++++++++++ .../ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml | 104 ++++++++++++++ .../ia/hhs/ssa/ia_ssa_rcf_supplement.yaml | 131 ++++++++++++++++++ .../ia/hhs/ssa/ia_ssa_smme_supplement.yaml | 71 ++++++++++ ...integration_dp_aged_couple_with_child.yaml | 39 ++++++ .../ia/hhs/ssa/integration_flh_resident.yaml | 30 ++++ .../ssa/integration_rcf_resident_2025.yaml | 32 +++++ .../ssa/integration_rcf_resident_2026.yaml | 32 +++++ .../ia/hhs/ssa/integration_single_blind.yaml | 29 ++++ .../ia/hhs/ssa/integration_smme_eligible.yaml | 30 ++++ .../hhs/ssa/test_2025_to_2026_transition.yaml | 64 +++++++++ .../ia/hhs/ssa/test_category_priority.yaml | 76 ++++++++++ .../ia/hhs/ssa/dp/ia_ssa_dp_configuration.py | 30 ++++ .../ia_ssa_dp_dependent_countable_income.py | 13 ++ .../dp/ia_ssa_dp_has_eligible_dependent.py | 12 ++ .../ia/hhs/ssa/dp/ia_ssa_dp_supplement.py | 29 ++++ .../ia/hhs/ssa/flh/ia_ssa_flh_supplement.py | 26 ++++ .../flh/ia_ssa_resides_in_family_life_home.py | 12 ++ .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 24 ++++ .../ia/hhs/ssa/ia_ssa_blind_supplement.py | 19 +++ .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 67 +++++++++ .../gov/states/ia/hhs/ssa/ia_ssa_eligible.py | 18 +++ .../ia/hhs/ssa/ia_ssa_resources_eligible.py | 17 +++ .../ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py | 13 ++ .../hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py | 31 +++++ ...a_ssa_needs_in_home_health_related_care.py | 12 ++ .../hhs/ssa/rcf/ia_ssa_rcf_cost_per_diem.py | 13 ++ .../ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py | 29 ++++ ...sa_resides_in_residential_care_facility.py | 13 ++ .../hhs/ssa/smme/ia_ssa_has_full_medicaid.py | 12 ++ .../ssa/smme/ia_ssa_has_medicare_part_b.py | 12 ++ .../ia/hhs/ssa/smme/ia_ssa_smme_eligible.py | 19 +++ .../ia/hhs/ssa/smme/ia_ssa_smme_supplement.py | 19 +++ .../income/spm_unit/spm_unit_benefits.py | 1 + 53 files changed, 1660 insertions(+), 1 deletion(-) create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/personal_needs_allowance.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/max_per_diem.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/personal_needs_allowance.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/smme.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_configuration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_dp_aged_couple_with_child.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_flh_resident.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2025.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2026.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_single_blind.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_smme_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_2025_to_2026_transition.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_category_priority.yaml create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_configuration.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_dependent_countable_income.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_has_eligible_dependent.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_resides_in_family_life_home.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_needs_in_home_health_related_care.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_cost_per_diem.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_resides_in_residential_care_facility.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py diff --git a/changelog.d/ia-ssp.added.md b/changelog.d/ia-ssp.added.md index 1f2ad14cdf9..a58a93e66bd 100644 --- a/changelog.d/ia-ssp.added.md +++ b/changelog.d/ia-ssp.added.md @@ -1 +1 @@ -Added Iowa State Supplementary Payment (SSP). +Added Iowa State Supplementary Assistance (SSA), covering the Blind, Dependent Person, Family-Life Home, In-Home Health-Related Care, Residential Care Facility, and Supplement for Medicare and Medicaid Eligibles supplements. diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index 9573ff8c17e..1758f7b9508 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -26,6 +26,8 @@ values: - al_ssp # Alaska benefits - ak_ssp + # Iowa benefits + - ia_ssa # Nebraska benefits - ne_child_care_subsidies # Massachusetts benefits @@ -57,6 +59,8 @@ values: - al_ssp # Alaska benefits - ak_ssp + # Iowa benefits + - ia_ssa # Nebraska benefits - ne_child_care_subsidies # North Carolina benefits diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml new file mode 100644 index 00000000000..0255a46fabe --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml @@ -0,0 +1,14 @@ +description: Iowa provides this amount as the blind supplement under the State Supplementary Assistance program. + +values: + 2017-07-01: 22 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA blind supplement amount + reference: + - title: Iowa Administrative Code 441—52.1(4) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml new file mode 100644 index 00000000000..1c10e013d08 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml @@ -0,0 +1,32 @@ +description: Iowa provides this amount as the dependent person assistance standard under the State Supplementary Assistance program. + +metadata: + unit: currency-USD + period: month + label: Iowa SSA dependent person assistance standard + breakdown: + - ia_ssa_dp_configuration + reference: + - title: Iowa Administrative Code 441—52.1(2) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance + +AGED_OR_DISABLED_WITH_DEPENDENT: + 2017-07-01: 1_470 + 2026-01-01: 1_512 +AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT: + 2017-07-01: 1_953 + 2026-01-01: 2_009 +BLIND_WITH_DEPENDENT: + 2017-07-01: 1_492 + 2026-01-01: 1_534 +BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: + 2017-07-01: 1_975 + # 2026 value as published by Iowa HHS — 53% increase vs 2025 $1,975 looks like possible typo; requires verification against Iowa HHS bulletin. + 2026-01-01: 3_031 +BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT: + 2017-07-01: 1_997 + 2026-01-01: 2_053 +NONE: + 2017-07-01: 0 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml new file mode 100644 index 00000000000..72fac83478a --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml @@ -0,0 +1,15 @@ +description: Iowa limits a dependent relative's countable income to this amount for dependent person eligibility under the State Supplementary Assistance program. + +values: + 2017-07-01: 503 + 2026-01-01: 518 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA dependent person dependent income limit + reference: + - title: Iowa Administrative Code 441—52.1(2) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml new file mode 100644 index 00000000000..fd23198c126 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml @@ -0,0 +1,15 @@ +description: Iowa limits the dependent person supplement to this amount per eligible person under the State Supplementary Assistance program. + +values: + 2017-07-01: 503 + 2026-01-01: 518 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA dependent person maximum payment per person + reference: + - title: Iowa Administrative Code 441—52.1(2) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml new file mode 100644 index 00000000000..bfc5624872f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml @@ -0,0 +1,15 @@ +description: Iowa provides this amount as the family-life home assistance standard under the State Supplementary Assistance program. + +values: + 2017-07-01: 1_129 + 2026-01-01: 1_156 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA family-life home assistance standard + reference: + - title: Iowa Administrative Code 441—52.1(1) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml new file mode 100644 index 00000000000..855050dde3e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml @@ -0,0 +1,14 @@ +description: Iowa limits the family-life home supplement to this amount under the State Supplementary Assistance program. + +values: + 2017-07-01: 142 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA family-life home maximum supplement + reference: + - title: Iowa Administrative Code 441—52.1(1) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/personal_needs_allowance.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/personal_needs_allowance.yaml new file mode 100644 index 00000000000..9202839b06c --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/personal_needs_allowance.yaml @@ -0,0 +1,15 @@ +description: Iowa provides this amount as the family-life home personal needs allowance under the State Supplementary Assistance program. + +values: + 2017-07-01: 126 + 2026-01-01: 130 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA family-life home personal needs allowance + reference: + - title: Iowa Administrative Code 441—52.1(1) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml new file mode 100644 index 00000000000..d57ec1a78a1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml @@ -0,0 +1,14 @@ +description: Iowa limits the in-home health-related care supplement and countable income to this amount when both members of a couple need care under the State Supplementary Assistance program. + +values: + 2017-07-01: 961.10 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA in-home health-related care maximum cost couple + reference: + - title: Iowa Administrative Code 441—177.4(1)(f) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2 + - title: Iowa Administrative Code 441—52.1(5) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml new file mode 100644 index 00000000000..b0ddf58aee5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml @@ -0,0 +1,14 @@ +description: Iowa limits the in-home health-related care supplement and countable income to this amount when one member of the household needs care under the State Supplementary Assistance program. + +values: + 2017-07-01: 480.55 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA in-home health-related care maximum cost single + reference: + - title: Iowa Administrative Code 441—177.4(1)(f) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2 + - title: Iowa Administrative Code 441—52.1(5) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml new file mode 100644 index 00000000000..122694f1f11 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml @@ -0,0 +1,14 @@ +description: Iowa uses this multiplier on the maximum per diem to determine the residential care facility monthly income limit under the State Supplementary Assistance program. + +values: + 2017-07-01: 31 + +metadata: + unit: day + period: year + label: Iowa SSA residential care facility days-per-month multiplier + reference: + - title: Iowa Administrative Code 441—51.4 + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf + - title: Iowa Administrative Code 441—52.1(3) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/max_per_diem.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/max_per_diem.yaml new file mode 100644 index 00000000000..e02b2623c69 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/max_per_diem.yaml @@ -0,0 +1,15 @@ +description: Iowa provides this amount as the maximum cost-related per diem for residential care facility residents under the State Supplementary Assistance program. + +values: + 2017-07-01: 37.60 + 2026-01-01: 38.47 + +metadata: + unit: currency-USD + period: day + label: Iowa SSA residential care facility maximum cost-related per diem + reference: + - title: Iowa Administrative Code 441—52.1(3) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/personal_needs_allowance.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/personal_needs_allowance.yaml new file mode 100644 index 00000000000..79f5b3e97d7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/personal_needs_allowance.yaml @@ -0,0 +1,17 @@ +description: Iowa provides this amount as the residential care facility personal needs allowance under the State Supplementary Assistance program. + +values: + 2017-07-01: 126 + 2026-01-01: 130 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA residential care facility personal needs allowance + reference: + - title: Iowa Administrative Code 441—52.1(3) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa Code Section 249.9A + href: https://www.legis.iowa.gov/docs/code/249.9A.pdf + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme.yaml new file mode 100644 index 00000000000..6d7efd04a40 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme.yaml @@ -0,0 +1,14 @@ +description: Iowa provides this amount as the supplement for Medicare and Medicaid eligibles under the State Supplementary Assistance program. + +values: + 2017-07-01: 1 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA Medicare and Medicaid eligibles supplement amount + reference: + - title: Iowa Administrative Code 441—52.1(7) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 + - title: Iowa HHS State Supplementary Assistance Standards + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml new file mode 100644 index 00000000000..fbf8c51ac5d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml @@ -0,0 +1,67 @@ +- name: Case 1, blind SSI-eligible adult receives flat 22 dollar supplement. + period: 2025-01 + input: + people: + person1: + age: 40 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_blind_supplement: [22] + +- name: Case 2, non-blind person receives no blind supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + is_blind: false + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_blind_supplement: [0] + +- name: Case 3, blind person not SSI-eligible receives no supplement. + period: 2025-01 + input: + people: + person1: + age: 40 + is_blind: true + is_ssi_aged_blind_disabled: false + is_ssi_eligible: false + meets_ssi_resource_test: false + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_blind_supplement: [0] + +- name: Case 4, blind person at 2026 still receives frozen 22 dollar supplement. + period: 2026-01 + input: + people: + person1: + age: 40 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_blind_supplement: [22] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_configuration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_configuration.yaml new file mode 100644 index 00000000000..7e33831e5a1 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_configuration.yaml @@ -0,0 +1,77 @@ +- name: Case 1, aged or disabled client with dependent. + period: 2025-01 + input: + people: + person1: + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_configuration: [AGED_OR_DISABLED_WITH_DEPENDENT] + +- name: Case 2, aged or disabled client with spouse and dependent. + period: 2025-01 + input: + people: + person1: + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_configuration: [AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT] + +- name: Case 3, blind client with dependent. + period: 2025-01 + input: + people: + person1: + ia_ssa_dp_configuration: BLIND_WITH_DEPENDENT + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_configuration: [BLIND_WITH_DEPENDENT] + +- name: Case 4, blind client with aged or disabled spouse and dependent. + period: 2025-01 + input: + people: + person1: + ia_ssa_dp_configuration: BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_configuration: [BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT] + +- name: Case 5, blind client with blind spouse and dependent. + period: 2025-01 + input: + people: + person1: + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_configuration: [BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT] + +- name: Case 6, person with no dependent relative. + period: 2025-01 + input: + people: + person1: + ia_ssa_dp_configuration: NONE + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_configuration: [NONE] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml new file mode 100644 index 00000000000..378620d0438 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml @@ -0,0 +1,91 @@ +- name: Case 1, person with no DP configuration gets zero supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_dp_configuration: NONE + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_supplement: [0] + +- name: Case 2, person not SSI-eligible gets zero DP supplement. + period: 2025-01 + input: + people: + person1: + age: 30 + is_ssi_aged_blind_disabled: false + is_ssi_eligible: false + meets_ssi_resource_test: false + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_supplement: [0] + +- name: Case 3, DP supplement capped at per-person maximum 503 dollars. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + households: + household: + members: [person1] + state_code: IA + output: + # Standard $1,997 minus federal SSI and income; well above $503 cap + ia_ssa_dp_supplement: [503] + +- name: Case 4, DP supplement cap rises to 518 dollars in 2026. + period: 2026-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_supplement: [518] + +- name: Case 5, dependent income above 503 limit disqualifies DP supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 600 + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_dp_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml new file mode 100644 index 00000000000..8b09fc1838a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml @@ -0,0 +1,63 @@ +- name: Case 1, SSI-eligible Iowa resident meets all criteria. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_eligible: [true] + +- name: Case 2, person not SSI-eligible is ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + is_ssi_aged_blind_disabled: false + is_ssi_eligible: false + meets_ssi_resource_test: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_eligible: [false] + +- name: Case 3, person fails resource test is ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: false + meets_ssi_resource_test: false + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_eligible: [false] + +- name: Case 4, non-Iowa resident is ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + households: + household: + members: [person1] + state_code: NY + output: + ia_ssa_eligible: [false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml new file mode 100644 index 00000000000..084499b9186 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml @@ -0,0 +1,70 @@ +- name: Case 1, FLH resident with zero income receives capped 142 dollar supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_family_life_home: true + households: + household: + members: [person1] + state_code: IA + output: + # standard $1,129 - federal SSI $967 - $20 disregard = $142 + # capped at $142 maximum + ia_ssa_flh_supplement: [142] + +- name: Case 2, person not in FLH receives zero FLH supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_family_life_home: false + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_flh_supplement: [0] + +- name: Case 3, FLH resident not SSI-eligible receives zero. + period: 2025-01 + input: + people: + person1: + age: 30 + is_ssi_aged_blind_disabled: false + is_ssi_eligible: false + meets_ssi_resource_test: false + ia_ssa_resides_in_family_life_home: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_flh_supplement: [0] + +- name: Case 4, FLH resident 2026 still capped at 142 dollars. + period: 2026-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_family_life_home: true + households: + household: + members: [person1] + state_code: IA + output: + # Cap is frozen at $142 even though standard and PNA rise in 2026 + ia_ssa_flh_supplement: [142] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml new file mode 100644 index 00000000000..7c2794958c8 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml @@ -0,0 +1,104 @@ +- name: Case 1, individual IHHRC cost below max pays actual cost. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 450 + households: + household: + members: [person1] + state_code: IA + output: + # Cost $450 is below max $480.55 -> pays actual $450 + ia_ssa_ihhrc_supplement: [450] + +- name: Case 2, individual IHHRC cost above max is capped at 480.55 dollars. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 600 + households: + household: + members: [person1] + state_code: IA + output: + # Cost $600 > max $480.55 -> capped + ia_ssa_ihhrc_supplement: [480.55] + +- name: Case 3, person does not need IHHRC receives zero supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: false + ia_ssa_ihhrc_cost_of_care: 400 + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_ihhrc_supplement: [0] + +- name: Case 4, person needing IHHRC but not SSI-eligible receives zero. + period: 2025-01 + input: + people: + person1: + age: 30 + is_ssi_aged_blind_disabled: false + is_ssi_eligible: false + meets_ssi_resource_test: false + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_ihhrc_supplement: [0] + +- name: Case 5, person with countable income above 480.55 single limit is ineligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + social_security_retirement: 20_000 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # SS $1,667/mo after SSI disregards exceeds single income cap $480.55 + # -> not in IHHRC category -> no supplement + ia_ssa_ihhrc_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml new file mode 100644 index 00000000000..9a4829105aa --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml @@ -0,0 +1,131 @@ +- name: Case 1, RCF resident at 2025 max per diem net of client participation. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + households: + household: + members: [person1] + state_code: IA + output: + # Cost of care = 31 * $37.60 = $1,165.60 + # Client participation = federal SSI $967 - PNA $126 = $841 + # Supplement = $1,165.60 - $841 = $324.60 + ia_ssa_rcf_supplement: [324.60] + +- name: Case 2, RCF per diem above max is capped at 37.60 dollars per day. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 50 + households: + household: + members: [person1] + state_code: IA + output: + # Capped cost = 31 * $37.60 = $1,165.60; CP $841; supplement $324.60 + ia_ssa_rcf_supplement: [324.60] + +- name: Case 3, person not in RCF receives zero supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: false + ia_ssa_rcf_cost_per_diem: 30 + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_rcf_supplement: [0] + +- name: Case 4, RCF resident at 2026 uses higher 38.47 dollar per diem. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 38.47 + households: + household: + members: [person1] + state_code: IA + output: + # Cost of care = 31 * $38.47 = $1,192.57 + # Client participation = federal SSI $994 - PNA $130 = $864 + # Supplement = $1,192.57 - $864 = $328.57 + ia_ssa_rcf_supplement: [328.57] + +- name: Case 5, RCF resident with zero reported per diem receives zero. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 0 + households: + household: + members: [person1] + state_code: IA + output: + # cost_of_care = 0; max(0, 0 - client_participation) = 0 + ia_ssa_rcf_supplement: [0] + +- name: Case 6, RCF resident with income above 31 times max per diem is ineligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + social_security_retirement: 30_000 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # SS $2,500/mo exceeds SSI FBR; client participation > + # 31 * $37.60 income limit -> not in RCF category -> no supplement + ia_ssa_rcf_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml new file mode 100644 index 00000000000..3dd3aa40f18 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml @@ -0,0 +1,71 @@ +- name: Case 1, aged person with Medicaid and Medicare Part B receives 1 dollar SMME. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_smme_supplement: [1] + +- name: Case 2, person without full Medicaid receives zero SMME. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_has_full_medicaid: false + ia_ssa_has_medicare_part_b: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_smme_supplement: [0] + +- name: Case 3, person without Medicare Part B receives zero SMME. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: false + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_smme_supplement: [0] + +- name: Case 4, non-SSI-eligible person receives zero SMME. + period: 2025-01 + input: + people: + person1: + age: 30 + is_ssi_aged_blind_disabled: false + is_ssi_eligible: false + meets_ssi_resource_test: false + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_smme_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_dp_aged_couple_with_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_dp_aged_couple_with_child.yaml new file mode 100644 index 00000000000..000638620d8 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_dp_aged_couple_with_child.yaml @@ -0,0 +1,39 @@ +- name: Case 1, aged client with aged spouse and dependent child at 2025 rates. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person2: + age: 68 + employment_income: 0 + ia_ssa_dp_configuration: NONE + person3: + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1, person2] + second_marital_unit: + members: [person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: IA + output: + # person1 qualifies for DP supplement at 2025 standard $1,953 (AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT) + # Standard - federal SSI - income; capped at $503/mo per person + ia_ssa_dp_supplement: [503, 0, 0] + # person1 category = DP + ia_ssa_category: [DP, NONE, NONE] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_flh_resident.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_flh_resident.yaml new file mode 100644 index 00000000000..bfc87cc6201 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_flh_resident.yaml @@ -0,0 +1,30 @@ +- name: Case 1, aged FLH resident with zero income receives 142 dollar capped supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills up to FBR; FLH standard $1,129 - federal SSI - $20 disregard > $142 + # Capped at $142 + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_flh_supplement: [142] + ia_ssa_category: [FLH] + ia_ssa: [142] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2025.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2025.yaml new file mode 100644 index 00000000000..5d566a09d9f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2025.yaml @@ -0,0 +1,32 @@ +- name: Case 1, aged RCF resident in 2025 at max per diem 37.60 dollars. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Cost of care = 31 * $37.60 = $1,165.60 + # Client participation = federal SSI $967 - PNA $126 = $841 + # Supplement = $1,165.60 - $841 = $324.60 + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_rcf_supplement: [324.60] + ia_ssa_category: [RCF] + ia_ssa: [324.60] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2026.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2026.yaml new file mode 100644 index 00000000000..b2994e3e069 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2026.yaml @@ -0,0 +1,32 @@ +- name: Case 1, aged RCF resident in 2026 at new max per diem 38.47 dollars. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 38.47 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Cost of care = 31 * $38.47 = $1,192.57 + # Client participation = federal SSI $994 - PNA $130 = $864 + # Supplement = $1,192.57 - $864 = $328.57 + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_rcf_supplement: [328.57] + ia_ssa_category: [RCF] + ia_ssa: [328.57] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_single_blind.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_single_blind.yaml new file mode 100644 index 00000000000..c6a51167cca --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_single_blind.yaml @@ -0,0 +1,29 @@ +- name: Case 1, single blind Iowa adult receiving SSI gets 22 dollar blind supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + is_blind: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_category: [BLIND] + ia_ssa_blind_supplement: [22] + # Blind is the only active category for this household + ia_ssa: [22] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_smme_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_smme_eligible.yaml new file mode 100644 index 00000000000..45655cedcff --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_smme_eligible.yaml @@ -0,0 +1,30 @@ +- name: Case 1, aged Iowan with Medicaid and Part B receives 1 dollar SMME. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Aged + full Medicaid + Part B + Iowa resident -> SMME $1/month + # SMME has lowest priority; applies only if no other category + is_ssi_eligible: [true] + ia_ssa_smme_supplement: [1] + ia_ssa_category: [SMME] + ia_ssa: [1] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_2025_to_2026_transition.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_2025_to_2026_transition.yaml new file mode 100644 index 00000000000..a0872e6c8d4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_2025_to_2026_transition.yaml @@ -0,0 +1,64 @@ +# Verifies parameter transitions at 2026-01-01: FLH standard, +# FLH personal needs allowance, RCF max per diem, RCF personal needs +# allowance, DP standards, and DP max payment cap. + +- name: Case 1, RCF per diem rises from 37.60 to 38.47 dollars in 2026. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 38.47 + households: + household: + members: [person1] + state_code: IA + output: + # Cost of care = 31 * $38.47 = $1,192.57 (2026 rate) + # Client participation = federal SSI $994 - PNA $130 = $864 + # Supplement = $1,192.57 - $864 = $328.57 + ia_ssa_rcf_supplement: [328.57] + +- name: Case 2, DP maximum per-person cap rises from 503 to 518 dollars in 2026. + period: 2026-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + households: + household: + members: [person1] + state_code: IA + output: + # BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT standard rises to $2,053 in 2026 + # but supplement is always capped at max per-person = $518 + ia_ssa_dp_supplement: [518] + +- name: Case 3, blind supplement remains 22 dollars across 2025 to 2026. + period: 2026-01 + input: + people: + person1: + age: 40 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + households: + household: + members: [person1] + state_code: IA + output: + # Blind amount frozen at $22 (no 2026 change) + ia_ssa_blind_supplement: [22] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_category_priority.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_category_priority.yaml new file mode 100644 index 00000000000..f258c67cd3c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_category_priority.yaml @@ -0,0 +1,76 @@ +# Verifies ia_ssa_category priority ordering: +# RCF > IHHRC > FLH > DP > BLIND > SMME > NONE + +- name: Case 1, RCF resident who is also blind gets RCF category not BLIND. + period: 2025-01 + input: + people: + person1: + age: 70 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + households: + household: + members: [person1] + state_code: IA + output: + # RCF outranks BLIND + ia_ssa_category: [RCF] + +- name: Case 2, FLH resident who is also blind gets FLH category not BLIND. + period: 2025-01 + input: + people: + person1: + age: 40 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_family_life_home: true + households: + household: + members: [person1] + state_code: IA + output: + # FLH outranks BLIND + ia_ssa_category: [FLH] + +- name: Case 3, person with only Medicaid and Part B gets SMME category. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + households: + household: + members: [person1] + state_code: IA + output: + # No other category applies -> SMME (lowest priority above NONE) + ia_ssa_category: [SMME] + +- name: Case 4, person in no qualifying category gets NONE. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_category: [NONE] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_configuration.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_configuration.py new file mode 100644 index 00000000000..964df6fc003 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_configuration.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class IASSADPConfiguration(Enum): + AGED_OR_DISABLED_WITH_DEPENDENT = "Aged/disabled client with dependent relative" + AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT = ( + "Aged/disabled client with aged/disabled spouse and dependent relative" + ) + BLIND_WITH_DEPENDENT = "Blind client with dependent relative" + BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT = ( + "Blind client with aged/disabled spouse and dependent relative" + ) + BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT = ( + "Blind client with blind spouse and dependent relative" + ) + NONE = "Not in a dependent person configuration" + + +class ia_ssa_dp_configuration(Variable): + value_type = Enum + entity = Person + definition_period = MONTH + label = "Iowa SSA dependent person configuration" + possible_values = IASSADPConfiguration + default_value = IASSADPConfiguration.NONE + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1", + "https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance", + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_dependent_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_dependent_countable_income.py new file mode 100644 index 00000000000..c0a4783a09b --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_dependent_countable_income.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ia_ssa_dp_dependent_countable_income(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA dependent person countable income" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=4" + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_has_eligible_dependent.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_has_eligible_dependent.py new file mode 100644 index 00000000000..9714555264f --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_has_eligible_dependent.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class ia_ssa_dp_has_eligible_dependent(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA has financially dependent relative" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py new file mode 100644 index 00000000000..8fed3b2fcdf --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class ia_ssa_dp_supplement(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA dependent person supplement" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1", + "https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance", + ) + + def formula(person, period, parameters): + category = person("ia_ssa_category", period) + in_category = category == category.possible_values.DP + p = parameters(period).gov.states.ia.hhs.ssa + configuration = person("ia_ssa_dp_configuration", period) + payment_standard = p.dp.assistance_standard[configuration] + uncapped_ssi = person("uncapped_ssi", period) + income_excess = max_(0, -uncapped_ssi) + federal_ssi = person("ssi", period) + raw_supplement = max_(0, payment_standard - income_excess - federal_ssi) + capped_supplement = min_(raw_supplement, p.dp.max_per_person_cap) + dependent_income = person("ia_ssa_dp_dependent_countable_income", period) + dependent_income_eligible = dependent_income < p.dp.dependent_income_limit + return in_category * dependent_income_eligible * capped_supplement diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py new file mode 100644 index 00000000000..73e46dc2a1a --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class ia_ssa_flh_supplement(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA family-life home supplement" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" + ) + + def formula(person, period, parameters): + category = person("ia_ssa_category", period) + in_category = category == category.possible_values.FLH + p = parameters(period).gov.states.ia.hhs.ssa + uncapped_ssi = person("uncapped_ssi", period) + income_excess = max_(0, -uncapped_ssi) + federal_ssi = person("ssi", period) + raw_supplement = max_( + 0, p.flh.assistance_standard - income_excess - federal_ssi + ) + capped_supplement = min_(raw_supplement, p.flh.max_supplement) + return in_category * capped_supplement diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_resides_in_family_life_home.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_resides_in_family_life_home.py new file mode 100644 index 00000000000..a83c515782b --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_resides_in_family_life_home.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class ia_ssa_resides_in_family_life_home(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA resides in certified family-life home" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py new file mode 100644 index 00000000000..ca32d2625a8 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class ia_ssa(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa State Supplementary Assistance" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/code/249.3.pdf", + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf", + "https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance", + ) + + adds = [ + "ia_ssa_blind_supplement", + "ia_ssa_dp_supplement", + "ia_ssa_flh_supplement", + "ia_ssa_ihhrc_supplement", + "ia_ssa_rcf_supplement", + "ia_ssa_smme_supplement", + ] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py new file mode 100644 index 00000000000..d2870bb415e --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ia_ssa_blind_supplement(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA blind supplement" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" + ) + + def formula(person, period, parameters): + category = person("ia_ssa_category", period) + in_category = category == category.possible_values.BLIND + p = parameters(period).gov.states.ia.hhs.ssa + return in_category * p.blind diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py new file mode 100644 index 00000000000..40b4b37ce77 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py @@ -0,0 +1,67 @@ +from policyengine_us.model_api import * + + +class IASSACategory(Enum): + RCF = "Residential care facility" + IHHRC = "In-home health-related care" + FLH = "Family-life home" + DP = "Dependent person" + BLIND = "Blind" + SMME = "Supplement for Medicare and Medicaid eligibles" + NONE = "Not in an Iowa SSA category" + + +class ia_ssa_category(Variable): + value_type = Enum + entity = Person + definition_period = MONTH + label = "Iowa SSA category" + possible_values = IASSACategory + default_value = IASSACategory.NONE + defined_for = StateCode.IA + reference = "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf" + + def formula(person, period, parameters): + eligible = person("ia_ssa_eligible", period) + p = parameters(period).gov.states.ia.hhs.ssa + uncapped_ssi = person("uncapped_ssi", period) + income_after_ssi_disregards = max_(0, -uncapped_ssi) + federal_ssi = person("ssi", period) + total_rcf_income = income_after_ssi_disregards + federal_ssi + in_rcf = person("ia_ssa_resides_in_residential_care_facility", period) + client_participation = max_( + 0, total_rcf_income - p.rcf.personal_needs_allowance + ) + rcf_income_threshold = p.rcf.days_multiplier * p.rcf.max_per_diem + rcf_income_eligible = client_participation < rcf_income_threshold + needs_ihhrc = person("ia_ssa_needs_in_home_health_related_care", period) + both_need_care = person.marital_unit.sum(needs_ihhrc) == 2 + ihhrc_income_cap = where( + both_need_care, p.ihhrc.max_cost_couple, p.ihhrc.max_cost_single + ) + ihhrc_income_eligible = income_after_ssi_disregards <= ihhrc_income_cap + in_flh = person("ia_ssa_resides_in_family_life_home", period) + has_dependent = person("ia_ssa_dp_has_eligible_dependent", period) + dp_configuration = person("ia_ssa_dp_configuration", period) + in_dp = dp_configuration != dp_configuration.possible_values.NONE + is_blind = person("is_blind", period.this_year) + smme_eligible = person("ia_ssa_smme_eligible", period) + return select( + [ + eligible & in_rcf & rcf_income_eligible, + eligible & needs_ihhrc & ihhrc_income_eligible, + eligible & in_flh, + eligible & has_dependent & in_dp, + eligible & is_blind, + eligible & smme_eligible, + ], + [ + IASSACategory.RCF, + IASSACategory.IHHRC, + IASSACategory.FLH, + IASSACategory.DP, + IASSACategory.BLIND, + IASSACategory.SMME, + ], + default=IASSACategory.NONE, + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py new file mode 100644 index 00000000000..862b6ae2517 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ia_ssa_eligible(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA eligible" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/code/249.3.pdf", + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf", + ) + + def formula(person, period, parameters): + categorically_eligible = person("is_ssi_eligible", period.this_year) + resources_eligible = person("ia_ssa_resources_eligible", period) + return categorically_eligible & resources_eligible diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py new file mode 100644 index 00000000000..0b2270534bf --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ia_ssa_resources_eligible(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA resources eligible" + defined_for = StateCode.IA + reference = "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf" + + def formula(person, period, parameters): + resources = person("ssi_countable_resources", period.this_year) + p = parameters(period).gov.ssa.ssi.eligibility.resources.limit + joint = person("ssi_claim_is_joint", period.this_year) + limit = where(joint, p.couple, p.individual) + return resources <= limit diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py new file mode 100644 index 00000000000..8fd70a1486d --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ia_ssa_ihhrc_cost_of_care(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA in-home health-related care monthly cost" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2" + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py new file mode 100644 index 00000000000..57b50773aab --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class ia_ssa_ihhrc_supplement(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA in-home health-related care supplement" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2" + ) + + def formula(person, period, parameters): + category = person("ia_ssa_category", period) + in_category = category == category.possible_values.IHHRC + p = parameters(period).gov.states.ia.hhs.ssa + cost = person("ia_ssa_ihhrc_cost_of_care", period) + both_need_care = ( + person.marital_unit.sum( + person("ia_ssa_needs_in_home_health_related_care", period) + ) + == 2 + ) + max_cost = where( + both_need_care, + p.ihhrc.max_cost_couple, + p.ihhrc.max_cost_single, + ) + return in_category * min_(cost, max_cost) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_needs_in_home_health_related_care.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_needs_in_home_health_related_care.py new file mode 100644 index 00000000000..cbb86aa4848 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_needs_in_home_health_related_care.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class ia_ssa_needs_in_home_health_related_care(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA needs in-home health-related care" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2" + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_cost_per_diem.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_cost_per_diem.py new file mode 100644 index 00000000000..ff95cb37af2 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_cost_per_diem.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ia_ssa_rcf_cost_per_diem(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA residential care facility actual per diem cost" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py new file mode 100644 index 00000000000..ad87fbf3286 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class ia_ssa_rcf_supplement(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA residential care facility supplement" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" + ) + + def formula(person, period, parameters): + category = person("ia_ssa_category", period) + in_category = category == category.possible_values.RCF + p = parameters(period).gov.states.ia.hhs.ssa + cost_per_diem = person("ia_ssa_rcf_cost_per_diem", period) + capped_per_diem = min_(cost_per_diem, p.rcf.max_per_diem) + cost_of_care = capped_per_diem * p.rcf.days_multiplier + uncapped_ssi = person("uncapped_ssi", period) + income_after_ssi_disregards = max_(0, -uncapped_ssi) + federal_ssi = person("ssi", period) + total_rcf_income = income_after_ssi_disregards + federal_ssi + client_participation = max_( + 0, total_rcf_income - p.rcf.personal_needs_allowance + ) + return in_category * max_(0, cost_of_care - client_participation) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_resides_in_residential_care_facility.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_resides_in_residential_care_facility.py new file mode 100644 index 00000000000..121b30f2451 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_resides_in_residential_care_facility.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ia_ssa_resides_in_residential_care_facility(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA resides in licensed residential care facility" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2", + "https://www.legis.iowa.gov/docs/code/135C.1.pdf", + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py new file mode 100644 index 00000000000..b222c2f8478 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class ia_ssa_has_full_medicaid(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA receives full Medicaid" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=7" + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py new file mode 100644 index 00000000000..8917d6d3640 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class ia_ssa_has_medicare_part_b(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA eligible for Medicare Part B" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=7" + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py new file mode 100644 index 00000000000..ebf4a988321 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ia_ssa_smme_eligible(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA SMME eligible" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2", + "https://www.legis.iowa.gov/docs/code/249.3.pdf", + ) + + def formula(person, period, parameters): + aged_or_disabled = person("is_ssi_aged_blind_disabled", period.this_year) + has_medicaid = person("ia_ssa_has_full_medicaid", period) + has_medicare = person("ia_ssa_has_medicare_part_b", period) + return aged_or_disabled & has_medicaid & has_medicare diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py new file mode 100644 index 00000000000..d770f33bcea --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ia_ssa_smme_supplement(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA SMME supplement" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2" + ) + + def formula(person, period, parameters): + category = person("ia_ssa_category", period) + in_category = category == category.possible_values.SMME + p = parameters(period).gov.states.ia.hhs.ssa + return in_category * p.smme 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 84cb7e78d39..060950bbcc9 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 @@ -15,6 +15,7 @@ def formula(spm_unit, period, parameters): "ga_ssp", "al_ssp", "ak_ssp", + "ia_ssa", "de_ssp", # Delaware benefits "ma_state_supplement", # Massachusetts benefits # California programs. From 00488db055ec0de6b8d482222a3fdf0b573630f2 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 17 Apr 2026 16:32:30 -0400 Subject: [PATCH 03/23] Apply /review-program critical fixes to IA SSA - Verified $3,031 DP BLIND_WITH_AGED configuration against Iowa HHS; replaced typo comment with verification note - Fixed 4 broken PDF page anchors (blind.yaml, SMME + DP docstrings) - Added formulas to ia_ssa_has_full_medicaid / ia_ssa_has_medicare_part_b delegating to federal medicaid_enrolled / medicare_enrolled, making SMME reachable in microsim - Added IAC 441-177.4(1)(c) own-home eligibility check to IHHRC category - Extracted ia_ssa_ihhrc_both_need_care variable; removed hard-coded 2 duplicated in two files - Reworked 5 non-functional ineligible tests to exercise ia_ssa_resources_eligible via ssi_countable_resources - Added ia_ssa_resources_eligible.yaml with boundary coverage (single/couple x below/at/above) - Added couple IHHRC test cases (at cap, above cap, one-spouse fallback) - Expanded category priority from 4 to 11 cases (IHHRC/DP/BLIND/SMME pairings) - Locked in blind combinability: blind RCF resident -> $0 blind supplement - Documented IAC 441-52.1(4) mutual exclusivity in ia_ssa_blind_supplement docstring - Consolidated test files to one-per-variable: merged integration_* and test_2025_to_2026_transition cases into variable-specific files with ssi + ia_ssa outputs side-by-side Co-Authored-By: Claude Opus 4.7 (1M context) --- .../gov/states/ia/hhs/ssa/blind.yaml | 2 +- .../ia/hhs/ssa/dp/assistance_standard.yaml | 2 +- .../ia/hhs/ssa/ia_ssa_blind_supplement.yaml | 66 +++++- .../states/ia/hhs/ssa/ia_ssa_category.yaml | 222 ++++++++++++++++++ .../ia/hhs/ssa/ia_ssa_dp_supplement.yaml | 52 +++- .../ia/hhs/ssa/ia_ssa_flh_supplement.yaml | 45 +++- .../ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml | 106 ++++++++- .../ia/hhs/ssa/ia_ssa_rcf_supplement.yaml | 66 +++++- .../ia/hhs/ssa/ia_ssa_resources_eligible.yaml | 82 +++++++ .../ia/hhs/ssa/ia_ssa_smme_supplement.yaml | 43 +++- ...integration_dp_aged_couple_with_child.yaml | 39 --- .../ia/hhs/ssa/integration_flh_resident.yaml | 30 --- .../ssa/integration_rcf_resident_2025.yaml | 32 --- .../ssa/integration_rcf_resident_2026.yaml | 32 --- .../ia/hhs/ssa/integration_single_blind.yaml | 29 --- .../ia/hhs/ssa/integration_smme_eligible.yaml | 30 --- .../hhs/ssa/test_2025_to_2026_transition.yaml | 64 ----- .../ia/hhs/ssa/test_category_priority.yaml | 76 ------ .../ia_ssa_dp_dependent_countable_income.py | 2 +- .../ia/hhs/ssa/ia_ssa_blind_supplement.py | 3 +- .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 7 +- .../ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py | 16 ++ .../hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py | 7 +- .../hhs/ssa/smme/ia_ssa_has_full_medicaid.py | 6 +- .../ssa/smme/ia_ssa_has_medicare_part_b.py | 6 +- 25 files changed, 690 insertions(+), 375 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_dp_aged_couple_with_child.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_flh_resident.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2025.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2026.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_single_blind.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_smme_eligible.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_2025_to_2026_transition.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_category_priority.yaml create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml index 0255a46fabe..044c3149ee0 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml @@ -9,6 +9,6 @@ metadata: label: Iowa SSA blind supplement amount reference: - title: Iowa Administrative Code 441—52.1(4) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 - title: Iowa HHS State Supplementary Assistance Standards href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml index 1c10e013d08..951c5d8b897 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml @@ -23,7 +23,7 @@ BLIND_WITH_DEPENDENT: 2026-01-01: 1_534 BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: 2017-07-01: 1_975 - # 2026 value as published by Iowa HHS — 53% increase vs 2025 $1,975 looks like possible typo; requires verification against Iowa HHS bulletin. + # Verified against Iowa HHS SSA payment standards page (hhs.iowa.gov/assistance-programs/state-supplementary-assistance): the 2026 value is $3,031, a ~53% jump over the 2017 baseline. Anomalous vs other configurations' ~2.85% COLA but published as stated. 2026-01-01: 3_031 BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT: 2017-07-01: 1_997 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml index fbf8c51ac5d..63c8b61b807 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml @@ -32,24 +32,80 @@ output: ia_ssa_blind_supplement: [0] -- name: Case 3, blind person not SSI-eligible receives no supplement. +- name: Case 3, blind person with excess resources receives no supplement. period: 2025-01 input: people: person1: age: 40 is_blind: true - is_ssi_aged_blind_disabled: false - is_ssi_eligible: false - meets_ssi_resource_test: false + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + ssi_countable_resources: 5_000 + households: + household: + members: [person1] + state_code: IA + output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_resources_eligible: [false] + ia_ssa_eligible: [false] + ia_ssa_blind_supplement: [0] + +- name: Case 4, blind RCF resident receives zero blind supplement (IAC 441-52.1(4) exclusivity). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 households: household: members: [person1] state_code: IA output: + # Per IAC 441-52.1(4), blind supplement only paid if not receiving + # another type of SSA. RCF category wins -> blind supplement is $0. + ia_ssa_category: [RCF] ia_ssa_blind_supplement: [0] -- name: Case 4, blind person at 2026 still receives frozen 22 dollar supplement. +- name: Case 5, single blind Iowan integration (federal SSI plus state blind supplement). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + is_blind: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_category: [BLIND] + ssi: [967] + ia_ssa_blind_supplement: [22] + ia_ssa: [22] + +- name: Case 6, blind person at 2026 still receives frozen 22 dollar supplement. period: 2026-01 input: people: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml new file mode 100644 index 00000000000..93ebd94b733 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml @@ -0,0 +1,222 @@ +# Verifies ia_ssa_category priority ordering: +# RCF > IHHRC > FLH > DP > BLIND > SMME > NONE + +- name: Case 1, RCF resident who is also blind gets RCF category not BLIND. + period: 2025-01 + input: + people: + person1: + age: 70 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + households: + household: + members: [person1] + state_code: IA + output: + # RCF outranks BLIND + ia_ssa_category: [RCF] + +- name: Case 2, FLH resident who is also blind gets FLH category not BLIND. + period: 2025-01 + input: + people: + person1: + age: 40 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_family_life_home: true + households: + household: + members: [person1] + state_code: IA + output: + # FLH outranks BLIND + ia_ssa_category: [FLH] + +- name: Case 3, person with only Medicaid and Part B gets SMME category. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + households: + household: + members: [person1] + state_code: IA + output: + # No other category applies -> SMME (lowest priority above NONE) + ia_ssa_category: [SMME] + +- name: Case 4, person in no qualifying category gets NONE. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + # Override federal medicare/medicaid defaults to exclude from SMME + ia_ssa_has_medicare_part_b: false + ia_ssa_has_full_medicaid: false + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_category: [NONE] + +- name: Case 5, FLH resident who also needs IHHRC gets FLH (IAC 441-177.4(1)(c) own-home rule). + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_resides_in_family_life_home: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + households: + household: + members: [person1] + state_code: IA + output: + # IHHRC requires living in own home; FLH resident fails that check -> FLH wins + ia_ssa_category: [FLH] + +- name: Case 6, person needing IHHRC who is also blind gets IHHRC not BLIND. + period: 2025-01 + input: + people: + person1: + age: 40 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + households: + household: + members: [person1] + state_code: IA + output: + # IHHRC outranks BLIND + ia_ssa_category: [IHHRC] + +- name: Case 7, person needing IHHRC with DP configuration gets IHHRC not DP. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + households: + household: + members: [person1] + state_code: IA + output: + # IHHRC outranks DP + ia_ssa_category: [IHHRC] + +- name: Case 8, person with DP configuration who is also blind gets DP not BLIND. + period: 2025-01 + input: + people: + person1: + age: 40 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_dp_configuration: BLIND_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + households: + household: + members: [person1] + state_code: IA + output: + # DP outranks BLIND + ia_ssa_category: [DP] + +- name: Case 9, blind person also SMME eligible gets BLIND not SMME. + period: 2025-01 + input: + people: + person1: + age: 70 + is_blind: true + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + households: + household: + members: [person1] + state_code: IA + output: + # BLIND outranks SMME + ia_ssa_category: [BLIND] + +- name: Case 10, DP-configured person also SMME eligible gets DP not SMME. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + households: + household: + members: [person1] + state_code: IA + output: + # DP outranks SMME + ia_ssa_category: [DP] + +- name: Case 11, person needing IHHRC also SMME eligible gets IHHRC not SMME. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + households: + household: + members: [person1] + state_code: IA + output: + # IHHRC outranks SMME + ia_ssa_category: [IHHRC] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml index 378620d0438..2dfedd2b2d7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml @@ -15,21 +15,23 @@ output: ia_ssa_dp_supplement: [0] -- name: Case 2, person not SSI-eligible gets zero DP supplement. +- name: Case 2, person with excess resources gets zero DP supplement. period: 2025-01 input: people: person1: - age: 30 - is_ssi_aged_blind_disabled: false - is_ssi_eligible: false - meets_ssi_resource_test: false + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + ssi_countable_resources: 5_000 ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT households: household: members: [person1] state_code: IA output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_eligible: [false] ia_ssa_dp_supplement: [0] - name: Case 3, DP supplement capped at per-person maximum 503 dollars. @@ -71,7 +73,45 @@ output: ia_ssa_dp_supplement: [518] -- name: Case 5, dependent income above 503 limit disqualifies DP supplement. +- name: Case 5, aged client with aged spouse and dependent child at 2025 rates integration. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person2: + age: 68 + employment_income: 0 + ia_ssa_dp_configuration: NONE + person3: + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1, person2] + second_marital_unit: + members: [person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: IA + output: + # person1: DP capped at $503; person2 defaults to SMME via federal medicaid/medicare enrolled; person3 child -> NONE + ia_ssa_category: [DP, SMME, NONE] + ia_ssa_dp_supplement: [503, 0, 0] + +- name: Case 6, dependent income above 503 limit disqualifies DP supplement. period: 2025-01 input: people: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml index 084499b9186..d6cb5b09cd7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml @@ -34,24 +34,57 @@ output: ia_ssa_flh_supplement: [0] -- name: Case 3, FLH resident not SSI-eligible receives zero. +- name: Case 3, FLH resident with excess resources receives zero. period: 2025-01 input: people: person1: - age: 30 - is_ssi_aged_blind_disabled: false - is_ssi_eligible: false - meets_ssi_resource_test: false + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + ssi_countable_resources: 5_000 ia_ssa_resides_in_family_life_home: true households: household: members: [person1] state_code: IA output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_eligible: [false] ia_ssa_flh_supplement: [0] -- name: Case 4, FLH resident 2026 still capped at 142 dollars. +- name: Case 4, aged FLH resident integration (federal SSI plus state SSA). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills to FBR; FLH supplement capped at $142 + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_category: [FLH] + ssi: [967] + ia_ssa_flh_supplement: [142] + ia_ssa: [142] + +- name: Case 5, FLH resident 2026 still capped at 142 dollars. period: 2026-01 input: people: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml index 7c2794958c8..34fbe83ce9d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml @@ -54,15 +54,15 @@ output: ia_ssa_ihhrc_supplement: [0] -- name: Case 4, person needing IHHRC but not SSI-eligible receives zero. +- name: Case 4, person needing IHHRC with excess resources receives zero. period: 2025-01 input: people: person1: - age: 30 - is_ssi_aged_blind_disabled: false - is_ssi_eligible: false - meets_ssi_resource_test: false + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + ssi_countable_resources: 5_000 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 400 households: @@ -70,9 +70,103 @@ members: [person1] state_code: IA output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_eligible: [false] ia_ssa_ihhrc_supplement: [0] -- name: Case 5, person with countable income above 480.55 single limit is ineligible. +- name: Case 5, couple both needing IHHRC use couple cap 961.10 dollars. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 900 + person2: + age: 68 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 900 + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Both need care -> couple cap $961.10; each cost $900 < cap -> $900 each + ia_ssa_ihhrc_both_need_care: [true, true] + ia_ssa_ihhrc_supplement: [900, 900] + +- name: Case 6, couple both needing IHHRC above couple cap capped at 961.10 dollars. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 1_500 + person2: + age: 68 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 1_500 + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Both need care -> couple cap $961.10; each cost $1500 > cap -> capped + ia_ssa_ihhrc_supplement: [961.10, 961.10] + +- name: Case 7, couple with only one spouse needing IHHRC uses single cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 800 + person2: + age: 68 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + ia_ssa_needs_in_home_health_related_care: false + ia_ssa_ihhrc_cost_of_care: 0 + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Only person1 needs care -> both_need_care false -> single cap $480.55 + ia_ssa_ihhrc_both_need_care: [false, false] + ia_ssa_ihhrc_supplement: [480.55, 0] + +- name: Case 8, person with countable income above 480.55 single limit is ineligible. period: 2025-01 absolute_error_margin: 0.01 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml index 9a4829105aa..a2df0b321dc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml @@ -99,7 +99,71 @@ # cost_of_care = 0; max(0, 0 - client_participation) = 0 ia_ssa_rcf_supplement: [0] -- name: Case 6, RCF resident with income above 31 times max per diem is ineligible. +- name: Case 6, aged RCF resident in 2025 integration (federal SSI plus state SSA). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills to 2025 FBR $967; RCF supplement = 31 * $37.60 - ($967 - $126) = $324.60 + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_category: [RCF] + ssi: [967] + ia_ssa_rcf_supplement: [324.60] + ia_ssa: [324.60] + +- name: Case 7, aged RCF resident in 2026 integration at new 38.47 dollar per diem. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 38.47 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills to 2026 FBR $994; RCF supplement = 31 * $38.47 - ($994 - $130) = $328.57 + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_category: [RCF] + ssi: [994] + ia_ssa_rcf_supplement: [328.57] + ia_ssa: [328.57] + +- name: Case 8, RCF resident with income above 31 times max per diem is ineligible. period: 2025-01 absolute_error_margin: 0.01 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml new file mode 100644 index 00000000000..494fe8f9bbe --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml @@ -0,0 +1,82 @@ +- name: Case 1, single person with resources at 2,000 limit is eligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 2_000 + ssi_claim_is_joint: false + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_resources_eligible: [true] + +- name: Case 2, single person with resources 1 dollar above 2,000 limit is ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 2_001 + ssi_claim_is_joint: false + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_resources_eligible: [false] + +- name: Case 3, single person with resources 1,500 dollars is eligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 1_500 + ssi_claim_is_joint: false + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_resources_eligible: [true] + +- name: Case 4, joint SSI couple at 3,000 limit is eligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 3_000 + ssi_claim_is_joint: true + person2: + age: 68 + ssi_countable_resources: 3_000 + ssi_claim_is_joint: true + households: + household: + members: [person1, person2] + state_code: IA + output: + ia_ssa_resources_eligible: [true, true] + +- name: Case 5, joint SSI couple 1 dollar above 3,000 limit is ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 3_001 + ssi_claim_is_joint: true + person2: + age: 68 + ssi_countable_resources: 3_001 + ssi_claim_is_joint: true + households: + household: + members: [person1, person2] + state_code: IA + output: + ia_ssa_resources_eligible: [false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml index 3dd3aa40f18..35ad665ef81 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml @@ -52,15 +52,46 @@ output: ia_ssa_smme_supplement: [0] -- name: Case 4, non-SSI-eligible person receives zero SMME. +- name: Case 4, aged Iowan with Medicaid and Part B integration (federal SSI plus SMME). period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: - age: 30 - is_ssi_aged_blind_disabled: false - is_ssi_eligible: false - meets_ssi_resource_test: false + age: 70 + employment_income: 0 + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_category: [SMME] + ssi: [967] + ia_ssa_smme_supplement: [1] + ia_ssa: [1] + +- name: Case 5, person with excess resources receives zero SMME. + period: 2025-01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + ssi_countable_resources: 5_000 ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true households: @@ -68,4 +99,6 @@ members: [person1] state_code: IA output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_eligible: [false] ia_ssa_smme_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_dp_aged_couple_with_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_dp_aged_couple_with_child.yaml deleted file mode 100644 index 000638620d8..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_dp_aged_couple_with_child.yaml +++ /dev/null @@ -1,39 +0,0 @@ -- name: Case 1, aged client with aged spouse and dependent child at 2025 rates. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 0 - person2: - age: 68 - employment_income: 0 - ia_ssa_dp_configuration: NONE - person3: - age: 10 - employment_income: 0 - marital_units: - first_marital_unit: - members: [person1, person2] - second_marital_unit: - members: [person3] - tax_units: - tax_unit: - members: [person1, person2, person3] - spm_units: - spm_unit: - members: [person1, person2, person3] - households: - household: - members: [person1, person2, person3] - state_code: IA - output: - # person1 qualifies for DP supplement at 2025 standard $1,953 (AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT) - # Standard - federal SSI - income; capped at $503/mo per person - ia_ssa_dp_supplement: [503, 0, 0] - # person1 category = DP - ia_ssa_category: [DP, NONE, NONE] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_flh_resident.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_flh_resident.yaml deleted file mode 100644 index bfc87cc6201..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_flh_resident.yaml +++ /dev/null @@ -1,30 +0,0 @@ -- name: Case 1, aged FLH resident with zero income receives 142 dollar capped supplement. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_family_life_home: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Federal SSI fills up to FBR; FLH standard $1,129 - federal SSI - $20 disregard > $142 - # Capped at $142 - is_ssi_eligible: [true] - ia_ssa_eligible: [true] - ia_ssa_flh_supplement: [142] - ia_ssa_category: [FLH] - ia_ssa: [142] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2025.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2025.yaml deleted file mode 100644 index 5d566a09d9f..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2025.yaml +++ /dev/null @@ -1,32 +0,0 @@ -- name: Case 1, aged RCF resident in 2025 at max per diem 37.60 dollars. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 37.60 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Cost of care = 31 * $37.60 = $1,165.60 - # Client participation = federal SSI $967 - PNA $126 = $841 - # Supplement = $1,165.60 - $841 = $324.60 - is_ssi_eligible: [true] - ia_ssa_eligible: [true] - ia_ssa_rcf_supplement: [324.60] - ia_ssa_category: [RCF] - ia_ssa: [324.60] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2026.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2026.yaml deleted file mode 100644 index b2994e3e069..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_rcf_resident_2026.yaml +++ /dev/null @@ -1,32 +0,0 @@ -- name: Case 1, aged RCF resident in 2026 at new max per diem 38.47 dollars. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 38.47 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Cost of care = 31 * $38.47 = $1,192.57 - # Client participation = federal SSI $994 - PNA $130 = $864 - # Supplement = $1,192.57 - $864 = $328.57 - is_ssi_eligible: [true] - ia_ssa_eligible: [true] - ia_ssa_rcf_supplement: [328.57] - ia_ssa_category: [RCF] - ia_ssa: [328.57] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_single_blind.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_single_blind.yaml deleted file mode 100644 index c6a51167cca..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_single_blind.yaml +++ /dev/null @@ -1,29 +0,0 @@ -- name: Case 1, single blind Iowa adult receiving SSI gets 22 dollar blind supplement. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 40 - is_blind: true - employment_income: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - is_ssi_eligible: [true] - ia_ssa_eligible: [true] - ia_ssa_category: [BLIND] - ia_ssa_blind_supplement: [22] - # Blind is the only active category for this household - ia_ssa: [22] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_smme_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_smme_eligible.yaml deleted file mode 100644 index 45655cedcff..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration_smme_eligible.yaml +++ /dev/null @@ -1,30 +0,0 @@ -- name: Case 1, aged Iowan with Medicaid and Part B receives 1 dollar SMME. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Aged + full Medicaid + Part B + Iowa resident -> SMME $1/month - # SMME has lowest priority; applies only if no other category - is_ssi_eligible: [true] - ia_ssa_smme_supplement: [1] - ia_ssa_category: [SMME] - ia_ssa: [1] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_2025_to_2026_transition.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_2025_to_2026_transition.yaml deleted file mode 100644 index a0872e6c8d4..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_2025_to_2026_transition.yaml +++ /dev/null @@ -1,64 +0,0 @@ -# Verifies parameter transitions at 2026-01-01: FLH standard, -# FLH personal needs allowance, RCF max per diem, RCF personal needs -# allowance, DP standards, and DP max payment cap. - -- name: Case 1, RCF per diem rises from 37.60 to 38.47 dollars in 2026. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 38.47 - households: - household: - members: [person1] - state_code: IA - output: - # Cost of care = 31 * $38.47 = $1,192.57 (2026 rate) - # Client participation = federal SSI $994 - PNA $130 = $864 - # Supplement = $1,192.57 - $864 = $328.57 - ia_ssa_rcf_supplement: [328.57] - -- name: Case 2, DP maximum per-person cap rises from 503 to 518 dollars in 2026. - period: 2026-01 - input: - people: - person1: - age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 0 - households: - household: - members: [person1] - state_code: IA - output: - # BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT standard rises to $2,053 in 2026 - # but supplement is always capped at max per-person = $518 - ia_ssa_dp_supplement: [518] - -- name: Case 3, blind supplement remains 22 dollars across 2025 to 2026. - period: 2026-01 - input: - people: - person1: - age: 40 - is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - households: - household: - members: [person1] - state_code: IA - output: - # Blind amount frozen at $22 (no 2026 change) - ia_ssa_blind_supplement: [22] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_category_priority.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_category_priority.yaml deleted file mode 100644 index f258c67cd3c..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/test_category_priority.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# Verifies ia_ssa_category priority ordering: -# RCF > IHHRC > FLH > DP > BLIND > SMME > NONE - -- name: Case 1, RCF resident who is also blind gets RCF category not BLIND. - period: 2025-01 - input: - people: - person1: - age: 70 - is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 37.60 - households: - household: - members: [person1] - state_code: IA - output: - # RCF outranks BLIND - ia_ssa_category: [RCF] - -- name: Case 2, FLH resident who is also blind gets FLH category not BLIND. - period: 2025-01 - input: - people: - person1: - age: 40 - is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_resides_in_family_life_home: true - households: - household: - members: [person1] - state_code: IA - output: - # FLH outranks BLIND - ia_ssa_category: [FLH] - -- name: Case 3, person with only Medicaid and Part B gets SMME category. - period: 2025-01 - input: - people: - person1: - age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: true - households: - household: - members: [person1] - state_code: IA - output: - # No other category applies -> SMME (lowest priority above NONE) - ia_ssa_category: [SMME] - -- name: Case 4, person in no qualifying category gets NONE. - period: 2025-01 - input: - people: - person1: - age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_category: [NONE] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_dependent_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_dependent_countable_income.py index c0a4783a09b..264f178c6e5 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_dependent_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_dependent_countable_income.py @@ -9,5 +9,5 @@ class ia_ssa_dp_dependent_countable_income(Variable): unit = USD defined_for = StateCode.IA reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=4" + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py index d2870bb415e..b3f41f85f94 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py @@ -6,10 +6,11 @@ class ia_ssa_blind_supplement(Variable): entity = Person definition_period = MONTH label = "Iowa SSA blind supplement" + documentation = "Iowa SSA blind supplement. Per IAC 441—52.1(4), a blind recipient receives this supplement only if they are not receiving another type of state supplementary assistance; this is enforced via ia_ssa_category returning BLIND only when no higher-priority category applies." unit = USD defined_for = StateCode.IA reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2" ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py index 40b4b37ce77..75088fc10e4 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py @@ -35,12 +35,15 @@ def formula(person, period, parameters): rcf_income_threshold = p.rcf.days_multiplier * p.rcf.max_per_diem rcf_income_eligible = client_participation < rcf_income_threshold needs_ihhrc = person("ia_ssa_needs_in_home_health_related_care", period) - both_need_care = person.marital_unit.sum(needs_ihhrc) == 2 + both_need_care = person("ia_ssa_ihhrc_both_need_care", period) ihhrc_income_cap = where( both_need_care, p.ihhrc.max_cost_couple, p.ihhrc.max_cost_single ) ihhrc_income_eligible = income_after_ssi_disregards <= ihhrc_income_cap in_flh = person("ia_ssa_resides_in_family_life_home", period) + # IAC 441—177.4(1)(c): IHHRC recipients must live in their own home, + # so exclude those residing in an RCF or family-life home. + in_own_home = ~in_rcf & ~in_flh has_dependent = person("ia_ssa_dp_has_eligible_dependent", period) dp_configuration = person("ia_ssa_dp_configuration", period) in_dp = dp_configuration != dp_configuration.possible_values.NONE @@ -49,7 +52,7 @@ def formula(person, period, parameters): return select( [ eligible & in_rcf & rcf_income_eligible, - eligible & needs_ihhrc & ihhrc_income_eligible, + eligible & needs_ihhrc & in_own_home & ihhrc_income_eligible, eligible & in_flh, eligible & has_dependent & in_dp, eligible & is_blind, diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py new file mode 100644 index 00000000000..d006f704db4 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class ia_ssa_ihhrc_both_need_care(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Iowa SSA IHHRC both spouses need in-home health-related care" + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2" + ) + + def formula(person, period, parameters): + needs_care = person("ia_ssa_needs_in_home_health_related_care", period) + return person.marital_unit.sum(needs_care) == 2 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py index 57b50773aab..74c881f3700 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py @@ -17,12 +17,7 @@ def formula(person, period, parameters): in_category = category == category.possible_values.IHHRC p = parameters(period).gov.states.ia.hhs.ssa cost = person("ia_ssa_ihhrc_cost_of_care", period) - both_need_care = ( - person.marital_unit.sum( - person("ia_ssa_needs_in_home_health_related_care", period) - ) - == 2 - ) + both_need_care = person("ia_ssa_ihhrc_both_need_care", period) max_cost = where( both_need_care, p.ihhrc.max_cost_couple, diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py index b222c2f8478..60f540c7319 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py @@ -6,7 +6,11 @@ class ia_ssa_has_full_medicaid(Variable): entity = Person definition_period = MONTH label = "Iowa SSA receives full Medicaid" + documentation = "Whether the person receives full Medicaid without a spend down or premium, as required for Iowa SSA SMME category (IAC 441—51.7(1)). Defaults to federal medicaid_enrolled, which does not distinguish full vs partial coverage; override for spend-down recipients." defined_for = StateCode.IA reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=7" + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" ) + + def formula(person, period, parameters): + return person("medicaid_enrolled", period.this_year) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py index 8917d6d3640..d11b9639327 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py @@ -6,7 +6,11 @@ class ia_ssa_has_medicare_part_b(Variable): entity = Person definition_period = MONTH label = "Iowa SSA eligible for Medicare Part B" + documentation = "Whether the person is enrolled in Medicare Part B, as required for Iowa SSA SMME category (IAC 441—51.7(4)). Defaults to federal medicare_enrolled, which covers Part A and/or B; override for Part-A-only recipients." defined_for = StateCode.IA reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=7" + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" ) + + def formula(person, period, parameters): + return person("medicare_enrolled", period.this_year) From b3896bccfff78947de30318514fffb04418b02d1 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 17 Apr 2026 17:07:12 -0400 Subject: [PATCH 04/23] Fix Iowa SSA income calculations and cap comparisons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prior formulas used `max(0, -uncapped_ssi) + ssi` as a proxy for total monthly income. That expression equals `|FBR − countable_income|`, not actual income, which caused material errors: - RCF eligibility and client participation understated income for anyone with outside income below the FBR, overpaying the supplement by hundreds and classifying high-income residents as eligible. - IHHRC cap (IAC 441—177.4(1)(f)) was compared against excess-over-FBR instead of monthly countable income, letting recipients with countable income far above the $480.55 cap qualify whenever they were below the FBR. - DP and FLH phase-out (federally-administered per POMS SI 01415.050.F) did not use the federal SSP formula, paying the full cap in income bands where the supplement should phase down dollar-for-dollar. Fixes: - RCF and IHHRC (state-administered) use monthly SSI countable income + federal SSI payment as total income, matching IAC 441—52.1 rules. - DP and FLH (federally-administered) use `max(0, total_standard − max(countable, FBR))`, matching POMS SSP rules. - Delete unused flh.personal_needs_allowance parameter (dead code — FLH assistance standard is a lumped sum that already includes the allowance). - Add regression tests for each bug. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../hhs/ssa/flh/personal_needs_allowance.yaml | 15 ----- .../ia/hhs/ssa/ia_ssa_dp_supplement.yaml | 34 ++++++++++ .../ia/hhs/ssa/ia_ssa_flh_supplement.yaml | 32 +++++++++ .../ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml | 33 ++++++++++ .../ia/hhs/ssa/ia_ssa_rcf_supplement.yaml | 66 ++++++++++++++++++- .../ia/hhs/ssa/dp/ia_ssa_dp_supplement.py | 14 ++-- .../ia/hhs/ssa/flh/ia_ssa_flh_supplement.py | 12 ++-- .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 17 +++-- .../ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py | 12 ++-- 9 files changed, 202 insertions(+), 33 deletions(-) delete mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/personal_needs_allowance.yaml diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/personal_needs_allowance.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/personal_needs_allowance.yaml deleted file mode 100644 index 9202839b06c..00000000000 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/personal_needs_allowance.yaml +++ /dev/null @@ -1,15 +0,0 @@ -description: Iowa provides this amount as the family-life home personal needs allowance under the State Supplementary Assistance program. - -values: - 2017-07-01: 126 - 2026-01-01: 130 - -metadata: - unit: currency-USD - period: month - label: Iowa SSA family-life home personal needs allowance - reference: - - title: Iowa Administrative Code 441—52.1(1) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa HHS State Supplementary Assistance Standards - href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml index 2dfedd2b2d7..6666683c6c2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml @@ -129,3 +129,37 @@ state_code: IA output: ia_ssa_dp_supplement: [0] + +- name: Case 7, DP supplement phases down when countable income exceeds FBR plus cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + social_security_retirement: 20_640 + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,720/mo SS gross -> $1,700/mo countable. Payment standard $1,997, + # FBR $967. Federally-administered formula: + # max(0, 1997 - max(1700, 967)) = $297 (under the $503 cap). + # Prior broken formula kept this at the full $503 cap. + ia_ssa_dp_supplement: [297] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml index d6cb5b09cd7..13856cfa172 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml @@ -101,3 +101,35 @@ output: # Cap is frozen at $142 even though standard and PNA rise in 2026 ia_ssa_flh_supplement: [142] + +- name: Case 6, FLH supplement phases down when countable income exceeds FBR. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + social_security_retirement: 12_840 + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,070/mo SS gross -> $1,050/mo countable. FLH assistance standard + # $1,129, FBR $967. Federally-administered formula: + # max(0, 1129 - max(1050, 967)) = $79 (under the $142 cap). + # Prior broken formula paid the full $142 cap. + ia_ssa_flh_supplement: [79] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml index 34fbe83ce9d..42a1584363f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml @@ -196,3 +196,36 @@ # SS $1,667/mo after SSI disregards exceeds single income cap $480.55 # -> not in IHHRC category -> no supplement ia_ssa_ihhrc_supplement: [0] + +- name: Case 9, IHHRC income cap enforced against countable income even when below FBR. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + social_security_retirement: 9_600 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $800/mo SS, countable $780/mo; below FBR $967 so the prior + # broken formula incorrectly made them IHHRC-eligible (it compared + # excess-over-FBR, which is 0 here). Correct check compares countable + # $780 against cap $480.55 -> ineligible for IHHRC. + ia_ssa_ihhrc_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml index a2df0b321dc..23ba3da6640 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml @@ -163,7 +163,71 @@ ia_ssa_rcf_supplement: [328.57] ia_ssa: [328.57] -- name: Case 8, RCF resident with income above 31 times max per diem is ineligible. +- name: Case 8b, RCF resident with 12000 dollar Social Security has participation that reflects total monthly income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + social_security_retirement: 12_000 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,000/mo SS, countable $980; no SSI (uncapped negative); total monthly + # income $980; client participation $980 - $126 = $854; supplement = + # $1,165.60 - $854 = $311.60. + ia_ssa_rcf_supplement: [311.60] + +- name: Case 9, RCF resident with 18000 dollar Social Security is ineligible because total income exceeds threshold. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_aged_blind_disabled: true + is_ssi_eligible: true + meets_ssi_resource_test: true + social_security_retirement: 18_000 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,500/mo SS, countable $1,480; client participation $1,354 > threshold + # $1,165.60 -> RCF ineligible; no RCF supplement. Prior broken formula kept + # this person in the RCF category because it understated income. + ia_ssa_rcf_supplement: [0] + +- name: Case 10, RCF resident with income above 31 times max per diem is ineligible. period: 2025-01 absolute_error_margin: 0.01 input: diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py index 8fed3b2fcdf..898720739fa 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py @@ -19,10 +19,16 @@ def formula(person, period, parameters): p = parameters(period).gov.states.ia.hhs.ssa configuration = person("ia_ssa_dp_configuration", period) payment_standard = p.dp.assistance_standard[configuration] - uncapped_ssi = person("uncapped_ssi", period) - income_excess = max_(0, -uncapped_ssi) - federal_ssi = person("ssi", period) - raw_supplement = max_(0, payment_standard - income_excess - federal_ssi) + # Iowa DP is federally-administered per POMS SI 01415.050.F. For + # federally-administered SSP, the state supplement equals + # max(0, total_standard − max(countable_income, FBR)): it stays at + # the full state amount while income is below the FBR and then phases + # down dollar-for-dollar as income rises above the FBR. + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + fbr = parameters(period).gov.ssa.ssi.amount.individual + raw_supplement = max_(0, payment_standard - max_(countable_monthly, fbr)) capped_supplement = min_(raw_supplement, p.dp.max_per_person_cap) dependent_income = person("ia_ssa_dp_dependent_countable_income", period) dependent_income_eligible = dependent_income < p.dp.dependent_income_limit diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py index 73e46dc2a1a..0cdf69d4ae0 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py @@ -16,11 +16,15 @@ def formula(person, period, parameters): category = person("ia_ssa_category", period) in_category = category == category.possible_values.FLH p = parameters(period).gov.states.ia.hhs.ssa - uncapped_ssi = person("uncapped_ssi", period) - income_excess = max_(0, -uncapped_ssi) - federal_ssi = person("ssi", period) + # Iowa FLH is federally-administered per POMS SI 01415.050.F. For + # federally-administered SSP, the state supplement equals + # max(0, total_standard − max(countable_income, FBR)). + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + fbr = parameters(period).gov.ssa.ssi.amount.individual raw_supplement = max_( - 0, p.flh.assistance_standard - income_excess - federal_ssi + 0, p.flh.assistance_standard - max_(countable_monthly, fbr) ) capped_supplement = min_(raw_supplement, p.flh.max_supplement) return in_category * capped_supplement diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py index 75088fc10e4..181dd2f6ea8 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py @@ -24,10 +24,15 @@ class ia_ssa_category(Variable): def formula(person, period, parameters): eligible = person("ia_ssa_eligible", period) p = parameters(period).gov.states.ia.hhs.ssa - uncapped_ssi = person("uncapped_ssi", period) - income_after_ssi_disregards = max_(0, -uncapped_ssi) - federal_ssi = person("ssi", period) - total_rcf_income = income_after_ssi_disregards + federal_ssi + # Monthly SSI countable income and federal SSI payment; both source + # variables are annual, so divide by 12 for use in monthly formulas. + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR + # Iowa-administered RCF client participation uses total monthly income + # (SSI countable + federal SSI payment), not the |FBR − income| V-shape. + total_rcf_income = countable_monthly + ssi_monthly in_rcf = person("ia_ssa_resides_in_residential_care_facility", period) client_participation = max_( 0, total_rcf_income - p.rcf.personal_needs_allowance @@ -39,7 +44,9 @@ def formula(person, period, parameters): ihhrc_income_cap = where( both_need_care, p.ihhrc.max_cost_couple, p.ihhrc.max_cost_single ) - ihhrc_income_eligible = income_after_ssi_disregards <= ihhrc_income_cap + # IAC 441—177.4(1)(f): cap is compared against the person's monthly + # countable income, not the excess over the federal SSI benefit rate. + ihhrc_income_eligible = countable_monthly <= ihhrc_income_cap in_flh = person("ia_ssa_resides_in_family_life_home", period) # IAC 441—177.4(1)(c): IHHRC recipients must live in their own home, # so exclude those residing in an RCF or family-life home. diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py index ad87fbf3286..e893d77cdeb 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py @@ -19,10 +19,14 @@ def formula(person, period, parameters): cost_per_diem = person("ia_ssa_rcf_cost_per_diem", period) capped_per_diem = min_(cost_per_diem, p.rcf.max_per_diem) cost_of_care = capped_per_diem * p.rcf.days_multiplier - uncapped_ssi = person("uncapped_ssi", period) - income_after_ssi_disregards = max_(0, -uncapped_ssi) - federal_ssi = person("ssi", period) - total_rcf_income = income_after_ssi_disregards + federal_ssi + # Iowa RCF client participation is "total monthly income minus the + # personal needs allowance" per IAC 441—52.1. Use SSI countable income + # plus the federal SSI payment as the monthly income proxy. + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR + total_rcf_income = countable_monthly + ssi_monthly client_participation = max_( 0, total_rcf_income - p.rcf.personal_needs_allowance ) From 1c795dd271ed143b3367cdbfe91248f4ed6d901e Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 20 Apr 2026 15:34:13 -0400 Subject: [PATCH 05/23] Add working references for Iowa SSP implementation Co-Authored-By: Claude Opus 4.7 (1M context) --- sources/working_references.md | 366 ++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 sources/working_references.md diff --git a/sources/working_references.md b/sources/working_references.md new file mode 100644 index 00000000000..1d81684d431 --- /dev/null +++ b/sources/working_references.md @@ -0,0 +1,366 @@ +# Iowa State Supplementary Assistance (SSA) — Working References + +Research compiled 2026-04-16 for PolicyEngine-US implementation. +Every PDF link uses `#page=NN` (file page, not printed page) unless the PDF is single-page. + +--- + +## 0. Program Identification + +- **Official name**: **State Supplementary Assistance (SSA)** — Iowa statutorily and operationally uses "State Supplementary Assistance", *not* "State Supplementary Payment". The program is sometimes shortened to "SSP" in colloquial use but Iowa Code chapter 249 title reads "STATE SUPPLEMENTARY ASSISTANCE". +- **Administering agency**: **Iowa Department of Health and Human Services (HHS)** — reorganized from the Iowa Department of Human Services (DHS) in 2023. The DHS employees' manual is now the "Iowa Department of Health and Human Services Employees' Manual" (Title 6, Chapter B). Many rules and form numbers still reference "DHS". +- **Dual federal/state administration**: + - **SSA-administered** (federal Social Security Administration issues payment on behalf of state): Mandatory State Supplement, Blind Supplement, Dependent Person (DP), Family-Life Home (FLH). + - **State-administered** (Iowa HHS issues payment): Residential Care Facility (RCF), In-Home Health-Related Care (IHHRC), Supplement for Medicare and Medicaid Eligibles (SMME). + - Source: IAC 441—50.2(1) paragraphs a–c; Employees' Manual 6-B p.2. +- **Legal basis**: Iowa Code Chapter 249; IAC 441 Chapters 50, 51, 52, 54, and 177; 20 CFR 416 Subpart T (§§ 416.2001–416.2099). + +--- + +## 1. Iowa Code (Statute) + +### 1.1 Iowa Code § 249.3 — Eligibility +- **Local file**: `/tmp/ia-ssp/code-249-3.pdf` (2 pages; text: `code-249-3.txt`) +- **URL**: https://www.legis.iowa.gov/docs/code/249.3.pdf +- **Key content**: Four subsection groups of eligible persons: + 1. "Essential person" grandfathered from December 1973 categorical assistance (OAA/AB/AD). + 2. Persons receiving care in a licensed adult foster home, boarding home, custodial home, or "another type of protective living arrangement", OR nursing care in the person's own home, who are receiving SSI or would receive SSI but for excess income. + 3. Persons living with a dependent spouse/parent/child/adult child, receiving SSI or would receive SSI but for excess income, with income insufficient to provide for the dependent. + 4. The "Supplement for Medicare and Medicaid Eligibles" (SMME) group — aged 65+ or disabled, living in own home/home of another/group living/medical facility, eligible for SSI but for excess income or SGA, already receiving full Medicaid, eligible for Medicare Part B, income between 120% FPL and Medicaid income limit. + +### 1.2 Iowa Code § 249.9A — Personal Needs Allowance +- **Local file**: `/tmp/ia-ssp/code-249-9A.pdf` (1 page; text: `code-249-9A.txt`) +- **URL**: https://www.legis.iowa.gov/docs/code/2025/249.9A.pdf +- **Key content**: The department shall increase the RCF personal needs allowance by the same percentage and at the same time as federal SSI/Social Security COLA. Added by 2024 Acts, ch 1157, §46. NEW section (2024). + +### 1.3 Iowa Code Chapter 249 (top level) +- The overall "State Supplementary Assistance" chapter title in the Iowa Code. Referred to in manual as "Iowa Code Chapter 249, 'State Supplemental Assistance'" (note: Code title uses "Supplementary"; manual labels with "Supplemental" — both appear). + +--- + +## 2. Iowa Administrative Code (Regulations) + +All chapters below live under **Iowa Administrative Code Title 441 — Human Services Department**, Title V "State Supplementary Assistance". + +### 2.1 IAC 441—Chapter 50 — Application for Assistance +- **Local file**: `/tmp/ia-ssp/iac-441-50.pdf` (4 pages; text: `iac-441-50.txt`) +- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.50.pdf +- **Rule 441—50.1** — Definitions of aged, blind, disabled, applicant, client, "Payment for a dependent relative", "Payment for a protective living arrangement" (family life home), "Payment for residential care". +- **Rule 441—50.2** — Application procedures; paragraphs 50.2(1)(a)–(c) specify federal-vs-state administration of each SSA supplement. +- Recent amendment: ARC 9304C, IAB 5/28/25, effective 7/2/25. + +### 2.2 IAC 441—Chapter 51 — Eligibility +- **Local file**: `/tmp/ia-ssp/iac-441-51.pdf` (~6 pages; text: `iac-441-51.txt`) +- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.51.pdf +- **Rule 441—51.2** — Must apply for all other benefits (SSI, FIP, etc.). +- **Rule 441—51.3** — Supplementation from non-federal sources counts as income, reducing SSA payment. +- **Rule 441—51.4** — Eligibility for residential care (licensed facility, physician's statement, income less than 31 × max per diem). +- **Rule 441—51.5** — Dependent relatives (income/resource rules, financial dependency definition). +- **Rule 441—51.6** — Iowa residency requirement. +- **Rule 441—51.7** — Eligibility for SMME (Medicaid eligibility, SSI-eligibility except SGA/income, not eligible under other SSA group, Medicare Part B, living arrangement, income between 120% FPL and Medicaid limit). +- **Rule 441—51.8** — Income from room and board. +- **Rule 441—51.9** — SSN requirement; overpayment recovery. +- Recent amendment: ARC 9305C, IAB 5/28/25, effective 8/1/25. + +### 2.3 IAC 441—Chapter 52 — Payment +- **Local file**: `/tmp/ia-ssp/iac-441-52.pdf` (~5 pages; text: `iac-441-52.txt`) +- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.52.pdf +- **Rule 441—52.1(249)** — **Assistance standards** (the core rate-setting rule). + - Key text (file page 1): "Assistance standards are the amounts of money allowed on a monthly basis to recipients of state supplementary assistance… **Current assistance standards will be published on the department's website.** Assistance standards will be adjusted annually to reflect cost-of-living adjustments (COLA) adopted by the Social Security Administration, in accordance with 20 CFR §416.2095 and 20 CFR §416.2096 as amended to March 15, 2022. Adjustments to the assistance standards based on COLA are effective January 1 of each year." + - **52.1(1) Protective living arrangement** — family-life home (cross-reference to 441—Chapter 111). + - **52.1(2) Dependent relative** — five household configuration categories (see §5 below for list). + - **52.1(3) Residential care** — Before 7/1/2017: flat per diem OR cost-related per diem. On/after 7/1/2017: cost-related (max per diem). Details six income disregards applied in order, reserve bed days, etc. + - **52.1(4) Blind** — "$22 per month" for blind recipients not receiving another type of SSA (this figure is literally in the rule text). + - **52.1(5) In-home, health-related care** — cross-reference to 441—Chapter 177. + - **52.1(6) Minimum income level cases** — December 1973 MIL preservation. + - **52.1(7) Supplement for Medicare and Medicaid eligibles** — "$1 per month" (literally in the rule text). +- Recent amendment: ARC 9306C, IAB 5/28/25, effective 8/1/25. + +### 2.4 IAC 441—Chapter 54 — Facility Participation +- **Local file**: `/tmp/ia-ssp/iac-441-54.pdf` (~3 pages; text: `iac-441-54.txt`) +- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.54.pdf +- Residential care facility participation rules (not critical to individual eligibility modeling). + +### 2.5 IAC 441—Chapter 177 — In-Home Health-Related Care (IHHRC) +- **Local file**: `/tmp/ia-ssp/iac-441-177.pdf` (~7 pages; text: `iac-441-177.txt`) +- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.177.pdf +- **Rule 441—177.4(1)(f)** — Countable income limits: **$480.55/month** for one person, **$961.10** if both spouses need care, with disregards in order: SSI standard (individual/couple), $65 + ½ earned income, SSI dependent allowance per dependent, unmet medical needs of ineligible spouse, unmet medical needs of applicant/recipient. +- **Rule 441—177.4(1)(g)** — Income deeming rules for children. +- **Rule 441—177.5** — Provider qualifications (age 18+, health assessment, training). +- **Rule 441—177.6** — Physician certification procedure (Form 470-0673). +- **Rule 441—177.7** — Home maintenance allowance and client participation. +- Recent amendment: ARC 6720C, IAB 11/30/22, effective 2/1/23. + +### 2.6 Archive/aggregator links (for verification only) +- Justia: https://regulations.justia.com/states/iowa/agency-441/title-xv/chapter-177/rule-441-177-4/ +- Cornell LII: https://www.law.cornell.edu/regulations/iowa/Iowa-Code-r-441-52.1 — note: Cornell text lags Iowa's IAB amendments. Always cross-check against the legis.iowa.gov PDF. + +--- + +## 3. Iowa HHS Employees' Manual (Policy Manual) + +### 3.1 Title 6, Chapter B — State Supplementary Assistance +- **Local file (two copies with same content)**: + - `/tmp/ia-ssp/6b-manual.pdf` (3,582 lines text, ~78 pages) — smaller file, older PDF build + - `/tmp/ia-ssp/info-2025-03-07.pdf` (3,663 lines text) — identical content +- **URL (small version)**: https://hhs.iowa.gov/media/3987/download +- **URL (March 7, 2025 revision)**: https://hhs.iowa.gov/media/15607/download?inline +- **Revision date**: March 7, 2025. +- **Page references** (use for `#page=NN`): + - **Overview & Legal Basis**: manual p.1 (PDF file page ~5). + - **Policies Applicable to All SSA / Eligibility requirements**: p.2 (PDF ~6). Resource limits $2,000 individual / $3,000 couple. Income must be less than standard for living arrangement. + - **Blind Supplement**: p.15–16. Confirms $22 blind special allowance; maximum income levels $989 individual, $1,472 one-blind-couple, $1,494 both-blind-couple (based on 2025 SSI standards $967/$1,450). + - **Dependent Person**: p.16–26. Dependent income must be <$503/month (2025 value, = SSI dependent allowance). Household income must be less than applicable assistance standard: + - Aged or disabled client and a dependent relative: **$1,470** (2025) + - Aged or disabled client, spouse aged 65+ or disabled, and a dependent relative: **$1,953** (2025) + - Blind client and a dependent relative: **$1,492** (2025) + - Blind client, aged or disabled spouse, and a dependent relative: **$1,975** (2025) + - Blind client, blind spouse, and a dependent relative: **$1,997** (2025) + - **Family-Life Home (FLH)**: p.26–32. Standard allowance **$1,129** (2025). Maximum payment $142 (not $162, to compensate for SSI's $20 disregard). Personal needs **$126** (2025). + - **In-Home Health-Related Care (IHHRC)**: p.32–46. Max cost of care $480.55/month single / $961.10/month couple-both-needing-care. Home maintenance allowance $967 individual / $1,450 couple / $483 per dependent (2025 SSI-linked). + - **Mandatory State Supplement**: p.47–50. December 1973 minimum-income-level preservation cases (legacy). + - **Residential Care Supplement (RCF)**: p.50–70. Flat per diem $17.86, max cost-related per diem **$37.60** (2025). Personal needs **$126** (2025). Client participation rules detailed on p.57–67. + - **Supplement for Medicare and Medicaid Eligibles (SMME)**: p.70–74. Fixed $1/month paid quarterly. Requires dual Medicare Part B + full Medicaid, income between 120% FPL and Medicaid limit, not eligible under another SSA group. + +### 3.2 Additional manual: April 11, 2025 revision +- **Local file**: `/tmp/ia-ssp/info-2025-04-11.pdf` +- **URL**: https://hhs.iowa.gov/media/15819/download?inline +- 4,377 lines — this is Title 8 Chapter E (Medicaid Income), which includes tangential SSA references; **not the SSA-specific chapter**. + +--- + +## 4. Informational Letters / Rate-setting Announcements + +### 4.1 Informational Letter No. 2651-MC-FFS (December 30, 2024) +- **Local file**: `/tmp/ia-ssp/il-2024-12-30.pdf` (2 pages; text: `il-2024-12-30.txt`) +- **URL**: https://secureapp.dhs.state.ia.us/IMPA/Information/ViewDocument.aspx?viewdocument=634b265a-2fa6-4fdb-a4ed-0ce94e32b993 +- **Content**: Effective January 1, 2025: + - RCF **maximum per diem rate**: $36.82 → **$37.60** + - **Flat per diem rate**: remains at **$17.86** (unchanged since 2/1/2004) + - **Personal needs allowance**: $123.00 → **$126.00** + - Based on "average Medicaid copays paid by RCF Medicaid members in SFY 2024 in conjunction with the COLA increase announced by SSA". + +--- + +## 5. Current 2026 Rates — Iowa HHS SSA Standards Page + +### 5.1 State Supplementary Assistance | Health & Human Services +- **URL**: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance +- **Effective**: January 1, 2026 +- **Single-page HTML** (no PDF anchor needed) + +**Family Home Life (FLH)** — Effective January 1, 2026 +| Component | Amount | +|---|---| +| Payment to Family | $1,026.00 | +| Personal Needs Allowance | $130.00 | +| Payment Standard (total) | $1,156.00 | + +**Dependent Person (DP)** — Effective January 1, 2026 +| Category | Income Standard | +|---|---| +| Maximum Payment (per person) | $518.00 | +| Aged or Disabled Client and Dependent Relative | $1,512.00 | +| Aged or Disabled Client, Eligible Spouse, and Dependent Relative | $2,009.00 | +| Blind Client and Dependent Relative | $1,534.00 | +| Blind Client, Aged or Disabled Spouse, and Dependent Relative | **$3,031.00** ⚠️ SUSPECTED TYPO — see §9 | +| Blind Client, Blind Spouse, and Dependent Relative | $2,053.00 | + +**Residential Care Facility (RCF)** — Effective January 1, 2026 +| Component | Amount | +|---|---| +| Personal Needs Allowance | $130.00 | +| Flat per Diem Rate | $17.86 | +| Maximum Cost-Related per Diem Rate | $38.47 | + +### 5.2 Current rates NOT published on the HHS SSA page +The HHS SSA page does not publish current-year values for: +- Blind supplement ($22/month — hardcoded in IAC 441—52.1(4)) +- In-Home Health-Related Care max cost-of-care ($480.55 / $961.10 — hardcoded in IAC 441—177.4(1)(f)) +- SMME payment ($1/month — hardcoded in IAC 441—52.1(7)) +- Home maintenance allowances ($967 / $1,450 / $483 — derived from federal SSI FBR) +- 2026 manual update with revised FLH/DP/IHHRC amounts (not yet published; March 7, 2025 is the latest) + +--- + +## 6. Historical Pamphlet: Comm. 18 (State Supplementary Assistance) + +- **Local file**: `/tmp/ia-ssp/comm18.pdf` (3 pages; text: `comm18.txt`) +- **URL**: https://hhs.iowa.gov/media/6413/download +- **Revision date**: Comm. 18 (Rev. 3/10) — March 2010 +- **Content**: Consumer-facing explanation of SSA. Lists 5 special-needs categories: + - Special Blind Allowance + - Residential Care + - Family-Life Home + - Dependent Relative + - In-Home Health-Related Care +- Note: Comm. 18 does NOT list the SMME ($1/month) supplement (which was added by 2003 Iowa legislation for the "pass-through" requirement) or the Mandatory State Supplement (1973 MIL grandfathered cases) — likely because this consumer pamphlet predates some additions. Authoritative list of SSA types is in the 6-B manual and IAC 441—52.1. + +--- + +## 7. SSA 2011 State Assistance Programs Report (Iowa) + +### 7.1 Availability +- **Primary URL (SSA)**: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.html — **403 blocked** to automated tools (including curl with browser UA) +- **Wayback Machine (working)**: https://web.archive.org/web/2024/https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.html +- **Extracted text**: `/tmp/ia-ssp/ssa-2011-ia.txt` (209 lines, complete) + +### 7.2 2011 Payment Levels (from Table 1 — verbatim) +Optional state supplementation payment levels, January 2011 (in dollars): + +| Living arrangement | State code | Combined federal+state (Individual) | Combined federal+state (Couple) | State supplementation (Individual) | +|---|---|---|---|---| +| Living independently (blind) | A | 696.00 | 1,055.00 (a) | 22.00 | +| Living in the household of another (blind) | B | 471.34 | 718.00 (a) | 22.00 | +| Living with a dependent person (Aged and disabled) | C | 1,018.00 | 1,355.00 | 344.00 | +| Living with a dependent person (Blind) | C | 1,040.00 | 1,399.00 | 366.00 | +| Family life or boarding home (Aged and disabled) | D | 816.00 | 1,652.00 | 142.00 | +| Family life or boarding home (Blind) | D | 838.00 | 1,696.00 | 164.00 | +| Living with a dependent person in the household of another (Aged and disabled) | H | 793.34 | 1,018.00 | 344.00 | +| Living with a dependent person in the household of another (Blind) | H | 815.34 | 1,062.00 | 366.00 | +| Family life or boarding home with 1/3 reduction (Aged and disabled) | I | 591.34 | 1,315.00 | 142.00 | +| Family life or boarding home with 1/3 reduction (Blind) | I | 613.34 | 1,359.00 | 164.00 | +| Residential care | . . . | 965.34 | . . . | 291.34 (b) | +| In-home health care | . . . | 1,154.55 | 1,972.10 (c) | 480.55 (d) | + +**Footnotes**: +- (a) "Payment level when both members of a couple are blind; when only one member is blind, payment is reduced by $22." +- (b) "Amount based on allowable costs of residential care (up to $28.14 per day), plus a personal needs allowance of $93 per month, minus the federal SSI payment. State administers payments." +- (c) "Payment is based on both members of a couple needing in-home health-related care. When one member needs care, payment is reduced by $480.55. State administers payments." +- (d) "Payment is based on actual cost of in-home health-related care up to a maximum of $480.55, plus basic federal benefit. State administers payments." + +### 7.3 2011 Recipient Counts (from Table 2) +| Living arrangement | State code | Total | Aged | Blind | Disabled Adults | Disabled Children | +|---|---|---|---|---|---|---| +| **All recipients** | — | **5,281** | 594 | 453 | 3,927 | 307 | +| Living independently (blind) | A | 535 | 0 | 424 | 0 | 111 | +| Living in the household of another (blind) | B | 10 | 0 | 9 | 0 | 1 | +| Living with a dependent person | C | 1,473 | 109 | 18 | 1,176 | 170 | +| Family life or boarding home | D and I | 4 | 0 | 0 | 4 | 0 | +| Living with a dependent person in the household of another | H | 1 | 1 | 0 | 0 | 0 | +| Residential care | — | 1,703 | 299 | — | 1,404 | 0 | +| In-home health care | — | 1,531 | 182 | — | 1,324 | 25 | +| Medicaid facility | — | 24 | 3 | 2 | 19 | 0 | + +### 7.4 Program administration notes (from SSA 2011 Iowa page, verbatim) +- Mandatory Minimum Supplementation: Social Security Administration. +- Optional State Supplementation: "State Department of Human Services administers supplemental payments for persons receiving residential or in-home health-related care, and persons who are eligible for the supplement for Medicare and Medicaid eligible. Social Security Administration administers all other supplemental payments." +- Effective dates: January 1, 1974 (blind); May 1, 1974 (aged and disabled); **October 1, 2003** (SMME — supplement for Medicare and Medicaid eligible). +- Statutory basis: Code of Iowa, chapter 249. +- Total expenditures: "State-administered payments for calendar year 2010 are not available, but $5,362,000 in federally administered payments were made to SSI recipients." + +**Note**: The SSA 2011 report is the **last state-by-state SSP report SSA published**; it was discontinued thereafter. Use this as the authoritative historical snapshot for rates/eligibility as of January 2011. + +### 7.5 Derivation of 2011 state-only portions from combined totals +Working from 2011 SSI FBR ($674 individual / $1,011 couple): +- Blind (Individual) state-only = $22 (directly stated) +- Living with dependent (Aged/Disabled), Individual: combined $1,018 − federal $674 = **$344 state portion** ✓ matches +- Family-life home (Aged/Disabled), Individual: combined $816 − federal $674 = **$142** ✓ matches +- Residential care, Individual: per footnote (b), cost-based formula; $28.14/day × 31 = $872.34 + $93 PNA = $965.34 total = $291.34 state portion (after federal SSI). + +--- + +## 8. Historical rates from Wayback Machine (IA HHS SSA page) + +The Iowa HHS SSA rates page has archived snapshots available at: +- 2024 snapshot: https://web.archive.org/web/2024/https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance (shows Jan 1, 2025 rates) +- 2025 snapshot: https://web.archive.org/web/2025/https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance (shows Jan 1, 2025 rates) + +**Note**: Pre-2024 snapshots of the current URL and of the older `dhs.iowa.gov/state-supplementary-assistance-program` URL were not available in Wayback (404). This limits ability to verify historical year-by-year amounts beyond the 6-B manual's current rates and the SSA 2011 report. + +**Iowa HHS rates comparison (2025 → 2026)**: +| Item | 2025 | 2026 | COLA-implied? | +|---|---|---|---| +| FLH Payment to Family | $1,003 | $1,026 | 2.29% (≈ 2.5% COLA) ✓ | +| FLH Personal Needs Allowance | $126 | $130 | 3.17% — higher than COLA | +| FLH Payment Standard | $1,129 | $1,156 | 2.39% ✓ | +| DP Maximum Payment | $503 | $518 | 2.98% ≈ 2.5% COLA ✓ | +| DP Aged/Disabled + dep | $1,470 | $1,512 | 2.86% ✓ | +| DP Aged/Disabled + spouse + dep | $1,953 | $2,009 | 2.87% ✓ | +| DP Blind + dep | $1,492 | $1,534 | 2.82% ✓ | +| DP Blind + A/D spouse + dep | $1,975 | **$3,031** | **53.5% ⚠️ TYPO SUSPECTED** | +| DP Blind + blind spouse + dep | $1,997 | $2,053 | 2.80% ✓ | +| RCF Personal Needs | $126 | $130 | 3.17% | +| RCF Flat per Diem | $17.86 | $17.86 | frozen since 2/1/2004 | +| RCF Max Cost-Related per Diem | $37.60 | $38.47 | 2.31% ✓ | + +--- + +## 9. Known Issues / Verification Flags + +### 9.1 Suspected typo on Iowa HHS SSA page (DP Blind + Aged/Disabled spouse + dep) +- 2025 value: $1,975 (from 6-B manual and 2024/2025 Wayback) +- 2026 value as published: **$3,031** +- Expected 2026 value from COLA: ~$2,031 (consistent with the 2.8% applied to other 2026 DP rows) +- **Likely explanation**: Transposition/typo where "$2,031" became "$3,031". +- **Recommended action**: Flag this in the PR description as a verification TODO. Before committing parameter values for 2026, email Iowa HHS or wait for the next 6-B manual revision to confirm. + +### 9.2 2026 manual not yet published +- Latest 6-B manual is **March 7, 2025**. For 2026 implementation, the current (Effective January 1, 2026) rates on the HHS SSA page are the only source for FLH/DP/RCF. +- Blind, IHHRC, and SMME rates are controlled by IAC (and frozen or COLA-indexed from federal SSI standards), so the 2025 manual is still authoritative for those. + +### 9.3 Historical rates before 2011 and between 2011–2024 +- SSA stopped publishing state-by-state SSP reports after January 2011. +- Iowa's 2015–2023 rate snapshots were not archived on Wayback Machine. +- Reconstruction would require either: + - Manual request to Iowa HHS for historical assistance standards schedule; OR + - Calculation by applying federal SSI COLA sequence to the 2011 figures forward (approximate, because some rates are not pure COLA — e.g., the $17.86 flat per diem has been frozen since 2/1/2004). + +--- + +## 10. Closed PR #7734 (mattunrath/ia-ssp) + +- **Branch**: `mattunrath/ia-ssp` on GitHub remote +- **Single commit**: `02a0314df9` "Initial commit for Iowa SSP implementation" dated 2026-03-07 +- **Content**: Branch was initialized but **never committed source or variable files**. Only commit message; no actual implementation, no `sources/` directory, no parameters. +- **Use**: **Do not copy** — branch has no content to copy. Sources were independently collected here. + +--- + +## 11. Other supporting material + +### 11.1 Iowa Legislature Budget Unit: State Supplementary Assistance (FT doc 16896) +- **Local file**: `/tmp/ia-ssp/budget-unit.pdf` (text: `budget-unit.txt`, 53 lines) +- **URL**: https://www.legis.iowa.gov/docs/publications/FT/16896.pdf +- Contains legislative budget overview of SSA appropriations. + +### 11.2 ARC 3715C — Iowa Administrative Rules Notice +- **URL**: https://rules.iowa.gov/Notice/Details/3715C +- Amendment notice referenced in IAC Chapter 52's revision history. Confirms the "periods of eligibility beginning July 1, 2017" transition to cost-related-only RCF reimbursement. + +### 11.3 WorkWorld Iowa SSA reference (secondary / for cross-verification only) +- **URL**: https://help.workworldapp.com/wwwebhelp/state_supplementary_assistance_eligibility_requirements_iowa.htm +- References: Iowa DHS Employees' Policy Manual Title 6 Chapter B; 20 CFR 416.2001; Iowa Code § 249.3. + +### 11.4 Iowa Admin. Code Justia portal (secondary / for cross-verification only) +- **URL**: https://regulations.justia.com/states/iowa/441/title-v/chapter-51/441-51-3/ + +### 11.5 Iowa HHS application forms (SSA application, not source for rates) +- English: https://hhs.iowa.gov/media/5825/download?inline +- Spanish: https://hhs.iowa.gov/media/5828/download?inline +- Medicaid brochure: https://hhs.iowa.gov/media/6420/download?inline +- Application portal: https://hhsservices.iowa.gov/apspssp/ssp.portal + +--- + +## 12. Fetch status summary + +### Successful fetches +- Iowa HHS SSA current rates page ✓ +- Iowa Code § 249.3 (PDF) ✓ +- Iowa Code § 249.9A (PDF) ✓ +- IAC Chapters 50, 51, 52, 54, 177 (PDFs) ✓ +- 6-B Employees' Manual (PDF) — full 78-page text extracted ✓ +- Comm. 18 pamphlet ✓ +- Informational Letter 2651-MC-FFS (Dec 30, 2024 — RCF rate update) ✓ +- Iowa Legislature budget FT document ✓ +- **SSA 2011 Iowa report via Wayback Machine** ✓ (after direct SSA 403) + +### Failed fetches (403/404) — CRITICAL for unreachable-reference checkpoint +- **`https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.html`** — SSA blocks automated tools with HTTP 403. **Resolution**: content was successfully retrieved via Wayback Machine at `https://web.archive.org/web/2024/https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.html`. If primary citation is needed, user may need to download the SSA URL manually in a browser. The Wayback version is byte-for-byte the same HTML. +- **Historical snapshots of `dhs.iowa.gov/state-supplementary-assistance-program`** — 404 on all Wayback years tried (2015, 2018, 2019, 2020, 2022). DHS→HHS reorganization likely destroyed older archives. **Impact**: cannot directly verify year-by-year FLH/DP/RCF rates from 2011 to 2024. Mitigation: use the 2011 SSA report for the 2011 baseline; the 2025 HHS page/Wayback snapshot for the 2024/2025 rates; and accept that 2012–2023 rates will need to be either reconstructed via COLA application to 2011 figures, or obtained via direct request to Iowa HHS. + +### No attempt made (not needed for this scope) +- Individual annual IAB notices filing COLA adjustments (dozens of ARC numbers listed in IAC Ch 52's amendment history — each year has one, and for current modeling the published HHS standards are sufficient). + +--- From 1397759de6ae29978372511f449b29e72c72b285 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 21 Apr 2026 18:53:10 -0400 Subject: [PATCH 06/23] Apply SSP checklist fixes to Iowa SSA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add IAC 441—51.7(6) 120% FPL income floor for SMME eligibility - Restructure smme.yaml to smme/ folder (amount.yaml + minimum_income_fpl_multiplier.yaml) - Remove documentation= field from 3 variables (not PolicyEngine convention) - Fix days_multiplier.yaml description wording - Update programs.yaml: Iowa SSA status in_progress -> complete, add variable=ia_ssa - Rewrite tests with realistic income inputs (age, social_security_retirement) instead of bypass inputs (is_ssi_eligible, meets_ssi_resource_test, is_ssi_aged_blind_disabled); verify full federal-state chain - Add boundary and negative cases (SMME 120% FPL boundary, IHHRC countable income cap, FLH phase-down) Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia/hhs/ssa/rcf/days_multiplier.yaml | 2 +- .../hhs/ssa/{smme.yaml => smme/amount.yaml} | 0 .../smme/minimum_income_fpl_multiplier.yaml | 12 ++ policyengine_us/programs.yaml | 7 +- .../ia/hhs/ssa/ia_ssa_blind_supplement.yaml | 85 +++++++-- .../states/ia/hhs/ssa/ia_ssa_category.yaml | 171 ++++++++++++++---- .../ia/hhs/ssa/ia_ssa_dp_supplement.yaml | 95 +++++++--- .../states/ia/hhs/ssa/ia_ssa_eligible.yaml | 92 ++++++++-- .../ia/hhs/ssa/ia_ssa_flh_supplement.yaml | 104 +++++++---- .../ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml | 128 ++++++++----- .../ia/hhs/ssa/ia_ssa_rcf_supplement.yaml | 162 +++++++---------- .../ia/hhs/ssa/ia_ssa_smme_supplement.yaml | 159 +++++++++++++--- .../ia/hhs/ssa/ia_ssa_blind_supplement.py | 1 - .../hhs/ssa/smme/ia_ssa_has_full_medicaid.py | 1 - .../ssa/smme/ia_ssa_has_medicare_part_b.py | 1 - .../ia/hhs/ssa/smme/ia_ssa_smme_eligible.py | 16 +- .../ia/hhs/ssa/smme/ia_ssa_smme_supplement.py | 2 +- 17 files changed, 724 insertions(+), 314 deletions(-) rename policyengine_us/parameters/gov/states/ia/hhs/ssa/{smme.yaml => smme/amount.yaml} (100%) create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml index 122694f1f11..7a3bd185ff9 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml @@ -1,4 +1,4 @@ -description: Iowa uses this multiplier on the maximum per diem to determine the residential care facility monthly income limit under the State Supplementary Assistance program. +description: Iowa uses this number of days per month to convert the maximum per diem to a monthly residential care income limit under the State Supplementary Assistance program. values: 2017-07-01: 31 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ia/hhs/ssa/smme.yaml rename to policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml new file mode 100644 index 00000000000..9296a4983ee --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml @@ -0,0 +1,12 @@ +description: Iowa uses this share of the federal poverty level as the minimum income threshold for supplement for Medicare and Medicaid eligibles under the State Supplementary Assistance program. + +values: + 2017-07-01: 1.2 + +metadata: + unit: /1 + period: year + label: Iowa SSA SMME minimum income FPL multiplier + reference: + - title: Iowa Administrative Code 441—51.7(6) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 8e1dedf0f8f..6cdb33e7798 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -632,9 +632,10 @@ programs: name: Hawaii OSS full_name: Hawaii Optional State Supplementation - state: IA - status: in_progress - name: Iowa SSP - full_name: Iowa State Supplemental Payment + status: complete + name: Iowa SSA + full_name: Iowa State Supplementary Assistance + variable: ia_ssa - state: ID status: complete name: Idaho AABD diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml index 63c8b61b807..b1c315ff6ba 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml @@ -1,30 +1,50 @@ -- name: Case 1, blind SSI-eligible adult receives flat 22 dollar supplement. +- name: Case 1, blind aged Iowan receives flat 22 dollar supplement plus federal SSI. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 40 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: + is_ssi_eligible: [true] + ssi: [967] + ia_ssa_eligible: [true] + ia_ssa_category: [BLIND] ia_ssa_blind_supplement: [22] + ia_ssa: [22] -- name: Case 2, non-blind person receives no blind supplement. +- name: Case 2, non-blind aged Iowan receives no blind supplement. period: 2025-01 input: people: person1: age: 70 is_blind: false - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -39,9 +59,17 @@ person1: age: 40 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true + employment_income: 0 ssi_countable_resources: 5_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -60,11 +88,18 @@ person1: age: 70 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_residential_care_facility: true ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -75,7 +110,7 @@ ia_ssa_category: [RCF] ia_ssa_blind_supplement: [0] -- name: Case 5, single blind Iowan integration (federal SSI plus state blind supplement). +- name: Case 5, blind Iowan with earnings still gets blind supplement. period: 2025-01 absolute_error_margin: 0.01 input: @@ -83,7 +118,10 @@ person1: age: 40 is_blind: true - employment_income: 0 + # Earned income: $500/mo; after blind/disabled working student? + # The blind supplement has no income test at the category level + # beyond SSI categorical eligibility (which ignores income). + employment_income: 6_000 marital_units: marital_unit: members: [person1] @@ -98,12 +136,11 @@ members: [person1] state_code: IA output: + # Still ssi_eligible (passes ABD + resources + immigration). is_ssi_eligible: [true] ia_ssa_eligible: [true] ia_ssa_category: [BLIND] - ssi: [967] ia_ssa_blind_supplement: [22] - ia_ssa: [22] - name: Case 6, blind person at 2026 still receives frozen 22 dollar supplement. period: 2026-01 @@ -112,12 +149,20 @@ person1: age: 40 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: + # Blind supplement frozen at $22 since 2017. ia_ssa_blind_supplement: [22] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml index 93ebd94b733..7e5e5ee5add 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml @@ -1,18 +1,29 @@ # Verifies ia_ssa_category priority ordering: # RCF > IHHRC > FLH > DP > BLIND > SMME > NONE +# +# Note: SMME requires income > 120% FPL (IAC 441—51.7(6)). 2025 FPL 1-person +# (contiguous US) = $15,650; 120% = $18,780/year or $1,565/month. - name: Case 1, RCF resident who is also blind gets RCF category not BLIND. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_residential_care_facility: true ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -28,10 +39,17 @@ person1: age: 40 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -40,23 +58,31 @@ # FLH outranks BLIND ia_ssa_category: [FLH] -- name: Case 3, person with only Medicaid and Part B gets SMME category. +- name: Case 3, aged person above 120% FPL with Medicaid and Part B gets SMME. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + social_security_retirement: 24_000 # $2,000/mo, above 120% FPL ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: - # No other category applies -> SMME (lowest priority above NONE) + # No other category applies; income above 120% FPL -> SMME ia_ssa_category: [SMME] - name: Case 4, person in no qualifying category gets NONE. @@ -65,12 +91,19 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 # Override federal medicare/medicaid defaults to exclude from SMME ia_ssa_has_medicare_part_b: false ia_ssa_has_full_medicaid: false + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -80,16 +113,24 @@ - name: Case 5, FLH resident who also needs IHHRC gets FLH (IAC 441-177.4(1)(c) own-home rule). period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_family_life_home: true ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -100,16 +141,24 @@ - name: Case 6, person needing IHHRC who is also blind gets IHHRC not BLIND. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 40 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -120,17 +169,25 @@ - name: Case 7, person needing IHHRC with DP configuration gets IHHRC not DP. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 400 ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT ia_ssa_dp_has_eligible_dependent: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -146,11 +203,18 @@ person1: age: 40 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_dp_configuration: BLIND_WITH_DEPENDENT ia_ssa_dp_has_eligible_dependent: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -159,18 +223,26 @@ # DP outranks BLIND ia_ssa_category: [DP] -- name: Case 9, blind person also SMME eligible gets BLIND not SMME. +- name: Case 9, blind person with SMME-eligible income gets BLIND not SMME. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 is_blind: true - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + social_security_retirement: 24_000 # > 120% FPL ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -179,19 +251,27 @@ # BLIND outranks SMME ia_ssa_category: [BLIND] -- name: Case 10, DP-configured person also SMME eligible gets DP not SMME. +- name: Case 10, DP-configured person with SMME-eligible income gets DP not SMME. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + social_security_retirement: 24_000 ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT ia_ssa_dp_has_eligible_dependent: true ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -200,23 +280,36 @@ # DP outranks SMME ia_ssa_category: [DP] -- name: Case 11, person needing IHHRC also SMME eligible gets IHHRC not SMME. +- name: Case 11, IHHRC person with SMME-eligible income gets IHHRC not SMME. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + # Note: IHHRC income cap is $480.55/mo countable, so this needs to + # be low enough to qualify for IHHRC. But we also want Medicaid + + # Part B to test that IHHRC still wins over SMME. Use zero income + # so IHHRC wins even though SMME condition could apply. + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 400 ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: - # IHHRC outranks SMME + # IHHRC outranks SMME (SMME not active here — income $0 below 120% FPL — + # but the priority order still applies even if SMME were active). ia_ssa_category: [IHHRC] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml index 6666683c6c2..36bed229ba3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml @@ -1,13 +1,26 @@ +# IAC 441—52.1(2): DP is federally-administered per POMS SI 01415.050.F. +# Federally-administered SSP formula: +# supplement = max(0, payment_standard - max(countable, FBR)) +# capped at max_per_person_cap ($503 in 2025, $518 in 2026). +# Also requires dependent's countable income < dependent_income_limit. + - name: Case 1, person with no DP configuration gets zero supplement. period: 2025-01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_dp_configuration: NONE + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -21,10 +34,19 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true + employment_income: 0 ssi_countable_resources: 5_000 ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -36,16 +58,24 @@ - name: Case 3, DP supplement capped at per-person maximum 503 dollars. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT ia_ssa_dp_has_eligible_dependent: true ia_ssa_dp_dependent_countable_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -56,16 +86,24 @@ - name: Case 4, DP supplement cap rises to 518 dollars in 2026. period: 2026-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT ia_ssa_dp_has_eligible_dependent: true ia_ssa_dp_dependent_countable_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -73,7 +111,7 @@ output: ia_ssa_dp_supplement: [518] -- name: Case 5, aged client with aged spouse and dependent child at 2025 rates integration. +- name: Case 5, aged client with aged spouse and dependent child integration. period: 2025-01 absolute_error_margin: 0.01 input: @@ -107,22 +145,33 @@ members: [person1, person2, person3] state_code: IA output: - # person1: DP capped at $503; person2 defaults to SMME via federal medicaid/medicare enrolled; person3 child -> NONE - ia_ssa_category: [DP, SMME, NONE] + # person1: DP capped at $503. + # person2: income above 120% FPL for household of 3 would be required + # for SMME ($26,650 × 1.2 / 12 = $2,665/mo); but income is $0, so not + # SMME-eligible -> NONE. + # person3: child -> NONE. + ia_ssa_category: [DP, NONE, NONE] ia_ssa_dp_supplement: [503, 0, 0] -- name: Case 6, dependent income above 503 limit disqualifies DP supplement. +- name: Case 6, dependent income above limit disqualifies DP supplement. period: 2025-01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 600 + ia_ssa_dp_dependent_countable_income: 600 # > $503 limit + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -130,17 +179,14 @@ output: ia_ssa_dp_supplement: [0] -- name: Case 7, DP supplement phases down when countable income exceeds FBR plus cap. +- name: Case 7, DP supplement phases down when countable income exceeds FBR. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - social_security_retirement: 20_640 + social_security_retirement: 20_640 # $1,720/mo ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT ia_ssa_dp_has_eligible_dependent: true ia_ssa_dp_dependent_countable_income: 0 @@ -161,5 +207,4 @@ # $1,720/mo SS gross -> $1,700/mo countable. Payment standard $1,997, # FBR $967. Federally-administered formula: # max(0, 1997 - max(1700, 967)) = $297 (under the $503 cap). - # Prior broken formula kept this at the full $503 cap. ia_ssa_dp_supplement: [297] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml index 8b09fc1838a..8a751e6e91d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_eligible.yaml @@ -1,63 +1,123 @@ -- name: Case 1, SSI-eligible Iowa resident meets all criteria. +- name: Case 1, aged Iowan meets SSI categorical eligibility. period: 2025-01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: + is_ssi_eligible: [true] ia_ssa_eligible: [true] -- name: Case 2, person not SSI-eligible is ineligible. +- name: Case 2, young non-disabled person is not SSA-eligible (not aged/blind/disabled). period: 2025-01 input: people: person1: age: 30 - is_ssi_aged_blind_disabled: false - is_ssi_eligible: false - meets_ssi_resource_test: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: + is_ssi_eligible: [false] ia_ssa_eligible: [false] -- name: Case 3, person fails resource test is ineligible. +- name: Case 3, aged Iowan with excess resources is ineligible. period: 2025-01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: false - meets_ssi_resource_test: false + employment_income: 0 + ssi_countable_resources: 5_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: + # Resources $5,000 > $2,000 individual limit -> fails resources test + ia_ssa_resources_eligible: [false] ia_ssa_eligible: [false] -- name: Case 4, non-Iowa resident is ineligible. +- name: Case 4, non-Iowa resident is ineligible (defined_for filter). period: 2025-01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: NY output: ia_ssa_eligible: [false] + +- name: Case 5, aged Iowan with high income still SSA-eligible (no state income test for eligibility itself). + period: 2025-01 + input: + people: + person1: + age: 70 + social_security_retirement: 24_000 # $2,000/mo -> no federal SSI + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # ia_ssa_eligible = is_ssi_eligible & resources_eligible. + # is_ssi_eligible does NOT include an income test -> true even with high income. + # Per IAC 441—51.2, applicants need only "apply for or receive" SSI. + is_ssi_eligible: [true] + ia_ssa_eligible: [true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml index 13856cfa172..3cb7ac886c4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml @@ -1,21 +1,39 @@ -- name: Case 1, FLH resident with zero income receives capped 142 dollar supplement. +# IAC 441—52.1(1): FLH is federally-administered per POMS SI 01415.050.F. +# Federally-administered SSP formula: +# supplement = max(0, assistance_standard - max(countable, FBR)) +# capped at max_supplement ($142). + +- name: Case 1, aged FLH resident with zero income (federal SSI plus capped state supplement). period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: - # standard $1,129 - federal SSI $967 - $20 disregard = $142 - # capped at $142 maximum + # Federal SSI fills to FBR $967; assistance standard $1,129; + # raw supplement = 1,129 - max(0, 967) = 162; capped at $142. + is_ssi_eligible: [true] + ssi: [967] + ia_ssa_eligible: [true] + ia_ssa_category: [FLH] ia_ssa_flh_supplement: [142] + ia_ssa: [142] - name: Case 2, person not in FLH receives zero FLH supplement. period: 2025-01 @@ -23,10 +41,17 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_family_life_home: false + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -40,10 +65,18 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true + employment_income: 0 ssi_countable_resources: 5_000 ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -53,8 +86,8 @@ ia_ssa_eligible: [false] ia_ssa_flh_supplement: [0] -- name: Case 4, aged FLH resident integration (federal SSI plus state SSA). - period: 2025-01 +- name: Case 4, FLH resident 2026 still capped at 142 dollars. + period: 2026-01 absolute_error_margin: 0.01 input: people: @@ -76,43 +109,45 @@ members: [person1] state_code: IA output: - # Federal SSI fills to FBR; FLH supplement capped at $142 - is_ssi_eligible: [true] - ia_ssa_eligible: [true] - ia_ssa_category: [FLH] - ssi: [967] + # Cap is frozen at $142 even though standard and PNA rise in 2026 ia_ssa_flh_supplement: [142] - ia_ssa: [142] -- name: Case 5, FLH resident 2026 still capped at 142 dollars. - period: 2026-01 +- name: Case 5, FLH supplement phases down when countable income exceeds FBR. + period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + social_security_retirement: 12_840 # $1,070/mo gross ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: - # Cap is frozen at $142 even though standard and PNA rise in 2026 - ia_ssa_flh_supplement: [142] + # $1,070/mo SS gross -> $1,050/mo countable (after $20 disregard). + # Assistance standard $1,129; FBR $967. + # max(0, 1129 - max(1050, 967)) = $79 (under the $142 cap). + ia_ssa_flh_supplement: [79] -- name: Case 6, FLH supplement phases down when countable income exceeds FBR. +- name: Case 6, FLH supplement is zero when countable income equals or exceeds standard. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - social_security_retirement: 12_840 + social_security_retirement: 14_400 # $1,200/mo gross ia_ssa_resides_in_family_life_home: true marital_units: marital_unit: @@ -128,8 +163,5 @@ members: [person1] state_code: IA output: - # $1,070/mo SS gross -> $1,050/mo countable. FLH assistance standard - # $1,129, FBR $967. Federally-administered formula: - # max(0, 1129 - max(1050, 967)) = $79 (under the $142 cap). - # Prior broken formula paid the full $142 cap. - ia_ssa_flh_supplement: [79] + # Countable $1,180/mo; standard $1,129; raw = max(0, 1129 - 1180) = 0. + ia_ssa_flh_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml index 42a1584363f..a52b0ff4aaf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml @@ -1,33 +1,54 @@ +# IAC 441—177.4(1)(f): IHHRC supplement pays actual cost up to max_cost_single +# ($480.55) or max_cost_couple ($961.10) when both spouses need care. +# IAC 441—177.4(1)(c): recipient must live in own home (not in RCF or FLH). +# Income cap: countable monthly income <= max_cost_single/couple. + - name: Case 1, individual IHHRC cost below max pays actual cost. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 450 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: - # Cost $450 is below max $480.55 -> pays actual $450 + # Cost $450 below max $480.55 -> pays actual $450 ia_ssa_ihhrc_supplement: [450] - name: Case 2, individual IHHRC cost above max is capped at 480.55 dollars. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 600 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -36,17 +57,24 @@ # Cost $600 > max $480.55 -> capped ia_ssa_ihhrc_supplement: [480.55] -- name: Case 3, person does not need IHHRC receives zero supplement. +- name: Case 3, person not needing IHHRC receives zero supplement. period: 2025-01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: false ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -60,11 +88,19 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true + employment_income: 0 ssi_countable_resources: 5_000 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -74,28 +110,30 @@ ia_ssa_eligible: [false] ia_ssa_ihhrc_supplement: [0] -- name: Case 5, couple both needing IHHRC use couple cap 961.10 dollars. +- name: Case 5, couple both needing IHHRC use couple cap. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 900 person2: age: 68 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 900 marital_units: marital_unit: members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: members: [person1, person2] @@ -112,21 +150,23 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 1_500 person2: age: 68 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 1_500 marital_units: marital_unit: members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: members: [person1, person2] @@ -142,21 +182,23 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 800 person2: age: 68 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_needs_in_home_health_related_care: false ia_ssa_ihhrc_cost_of_care: 0 marital_units: marital_unit: members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: members: [person1, person2] @@ -166,17 +208,14 @@ ia_ssa_ihhrc_both_need_care: [false, false] ia_ssa_ihhrc_supplement: [480.55, 0] -- name: Case 8, person with countable income above 480.55 single limit is ineligible. +- name: Case 8, person with countable income above single cap is ineligible. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - social_security_retirement: 20_000 + social_security_retirement: 20_000 # $1,667/mo gross ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 400 marital_units: @@ -193,21 +232,18 @@ members: [person1] state_code: IA output: - # SS $1,667/mo after SSI disregards exceeds single income cap $480.55 + # Countable $1,647/mo exceeds single income cap $480.55 # -> not in IHHRC category -> no supplement ia_ssa_ihhrc_supplement: [0] -- name: Case 9, IHHRC income cap enforced against countable income even when below FBR. +- name: Case 9, IHHRC income cap enforced against countable income even below FBR. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - social_security_retirement: 9_600 + social_security_retirement: 9_600 # $800/mo gross ia_ssa_needs_in_home_health_related_care: true ia_ssa_ihhrc_cost_of_care: 400 marital_units: @@ -224,8 +260,6 @@ members: [person1] state_code: IA output: - # $800/mo SS, countable $780/mo; below FBR $967 so the prior - # broken formula incorrectly made them IHHRC-eligible (it compared - # excess-over-FBR, which is 0 here). Correct check compares countable - # $780 against cap $480.55 -> ineligible for IHHRC. + # $800/mo SS gross, countable $780/mo; below FBR $967, but IHHRC cap + # compares countable $780 against $480.55 -> exceeds cap -> ineligible. ia_ssa_ihhrc_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml index 23ba3da6640..c9217c83709 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml @@ -1,24 +1,40 @@ -- name: Case 1, RCF resident at 2025 max per diem net of client participation. +# IAC 441—52.1(3): payment in RCF = (31 * max_per_diem) - client_participation +# where client_participation = total_monthly_income - personal_needs_allowance. +# Total income = SSI-countable income + federal SSI payment. +# RCF income eligibility: client_participation < 31 * max_per_diem. + +- name: Case 1, aged RCF resident with no income (SSI fills to FBR). period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_residential_care_facility: true ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: - # Cost of care = 31 * $37.60 = $1,165.60 - # Client participation = federal SSI $967 - PNA $126 = $841 - # Supplement = $1,165.60 - $841 = $324.60 + # Federal SSI fills to 2025 FBR $967; RCF supplement = + # 31 * $37.60 - ($967 - $126) = $1,165.60 - $841 = $324.60 + is_ssi_eligible: [true] + ssi: [967] + ia_ssa_eligible: [true] + ia_ssa_category: [RCF] ia_ssa_rcf_supplement: [324.60] + ia_ssa: [324.60] - name: Case 2, RCF per diem above max is capped at 37.60 dollars per day. period: 2025-01 @@ -27,11 +43,18 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_residential_care_facility: true ia_ssa_rcf_cost_per_diem: 50 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -46,61 +69,27 @@ people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + employment_income: 0 ia_ssa_resides_in_residential_care_facility: false ia_ssa_rcf_cost_per_diem: 30 - households: - household: + marital_units: + marital_unit: members: [person1] - state_code: IA - output: - ia_ssa_rcf_supplement: [0] - -- name: Case 4, RCF resident at 2026 uses higher 38.47 dollar per diem. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 38.47 - households: - household: + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: members: [person1] - state_code: IA - output: - # Cost of care = 31 * $38.47 = $1,192.57 - # Client participation = federal SSI $994 - PNA $130 = $864 - # Supplement = $1,192.57 - $864 = $328.57 - ia_ssa_rcf_supplement: [328.57] - -- name: Case 5, RCF resident with zero reported per diem receives zero. - period: 2025-01 - input: - people: - person1: - age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 0 households: household: members: [person1] state_code: IA output: - # cost_of_care = 0; max(0, 0 - client_participation) = 0 ia_ssa_rcf_supplement: [0] -- name: Case 6, aged RCF resident in 2025 integration (federal SSI plus state SSA). - period: 2025-01 +- name: Case 4, aged RCF resident in 2026 uses higher 38.47 dollar per diem. + period: 2026-01 absolute_error_margin: 0.01 input: people: @@ -108,7 +97,7 @@ age: 70 employment_income: 0 ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 37.60 + ia_ssa_rcf_cost_per_diem: 38.47 marital_units: marital_unit: members: [person1] @@ -123,24 +112,22 @@ members: [person1] state_code: IA output: - # Federal SSI fills to 2025 FBR $967; RCF supplement = 31 * $37.60 - ($967 - $126) = $324.60 + # Federal SSI fills to 2026 FBR $994; RCF supplement = + # 31 * $38.47 - ($994 - $130) = $1,192.57 - $864 = $328.57 is_ssi_eligible: [true] - ia_ssa_eligible: [true] + ssi: [994] ia_ssa_category: [RCF] - ssi: [967] - ia_ssa_rcf_supplement: [324.60] - ia_ssa: [324.60] + ia_ssa_rcf_supplement: [328.57] -- name: Case 7, aged RCF resident in 2026 integration at new 38.47 dollar per diem. - period: 2026-01 - absolute_error_margin: 0.01 +- name: Case 5, RCF resident with zero reported per diem receives zero. + period: 2025-01 input: people: person1: age: 70 employment_income: 0 ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 38.47 + ia_ssa_rcf_cost_per_diem: 0 marital_units: marital_unit: members: [person1] @@ -155,25 +142,17 @@ members: [person1] state_code: IA output: - # Federal SSI fills to 2026 FBR $994; RCF supplement = 31 * $38.47 - ($994 - $130) = $328.57 - is_ssi_eligible: [true] - ia_ssa_eligible: [true] - ia_ssa_category: [RCF] - ssi: [994] - ia_ssa_rcf_supplement: [328.57] - ia_ssa: [328.57] + # cost_of_care = 0; max(0, 0 - client_participation) = 0 + ia_ssa_rcf_supplement: [0] -- name: Case 8b, RCF resident with 12000 dollar Social Security has participation that reflects total monthly income. +- name: Case 6, RCF resident with 12000 dollar Social Security has higher client participation. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - social_security_retirement: 12_000 + social_security_retirement: 12_000 # $1,000/mo ia_ssa_resides_in_residential_care_facility: true ia_ssa_rcf_cost_per_diem: 37.60 marital_units: @@ -190,22 +169,19 @@ members: [person1] state_code: IA output: - # $1,000/mo SS, countable $980; no SSI (uncapped negative); total monthly - # income $980; client participation $980 - $126 = $854; supplement = - # $1,165.60 - $854 = $311.60. + # $1,000/mo SS, countable $980; no SSI (countable > FBR minus $0 state + # standard); total monthly income $980; client participation + # $980 - $126 = $854; supplement = $1,165.60 - $854 = $311.60. ia_ssa_rcf_supplement: [311.60] -- name: Case 9, RCF resident with 18000 dollar Social Security is ineligible because total income exceeds threshold. +- name: Case 7, RCF resident with income above 31 times max per diem is ineligible. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - social_security_retirement: 18_000 + social_security_retirement: 30_000 ia_ssa_resides_in_residential_care_facility: true ia_ssa_rcf_cost_per_diem: 37.60 marital_units: @@ -222,22 +198,18 @@ members: [person1] state_code: IA output: - # $1,500/mo SS, countable $1,480; client participation $1,354 > threshold - # $1,165.60 -> RCF ineligible; no RCF supplement. Prior broken formula kept - # this person in the RCF category because it understated income. + # SS $2,500/mo exceeds SSI FBR; client participation > + # 31 * $37.60 income limit -> not in RCF category -> no supplement ia_ssa_rcf_supplement: [0] -- name: Case 10, RCF resident with income above 31 times max per diem is ineligible. +- name: Case 8, RCF resident with excess resources receives zero supplement. period: 2025-01 - absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - social_security_retirement: 30_000 + employment_income: 0 + ssi_countable_resources: 5_000 ia_ssa_resides_in_residential_care_facility: true ia_ssa_rcf_cost_per_diem: 37.60 marital_units: @@ -254,6 +226,6 @@ members: [person1] state_code: IA output: - # SS $2,500/mo exceeds SSI FBR; client participation > - # 31 * $37.60 income limit -> not in RCF category -> no supplement + # Resources $5,000 > $2,000 limit -> ia_ssa_eligible false + ia_ssa_eligible: [false] ia_ssa_rcf_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml index 35ad665ef81..3bdef0fc27f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml @@ -1,67 +1,110 @@ -- name: Case 1, aged person with Medicaid and Medicare Part B receives 1 dollar SMME. +# SMME is a $1/month technical SSP pathway for people who meet all SSI +# categorical eligibility (aged/blind/disabled, resources, immigration) but +# whose income exceeds the federal SSI benefit rate. Per IAC 441—51.7(6), +# income must exceed 120% of the federal poverty level. 2025 FPL (1 person, +# contiguous US) = $15,650; 120% = $18,780/year or $1,565/month. + +- name: Case 1, aged Iowan with income above 120% FPL, full Medicaid and Part B. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true + social_security_retirement: 24_000 # $2,000/month ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: + # Income $2,000/mo; countable $1,980 after $20 exclusion; + # 120% FPL for 1 person (2025, contiguous) = $1,565/mo; exceeds threshold. + # No SSI (countable > FBR $967). SMME pays $1. + is_ssi_eligible: [true] + ssi: [0] + ia_ssa_eligible: [true] + ia_ssa_category: [SMME] ia_ssa_smme_supplement: [1] + ia_ssa: [1] -- name: Case 2, person without full Medicaid receives zero SMME. +- name: Case 2, aged Iowan with low income (below 120% FPL) is not SMME-eligible. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_has_full_medicaid: false + social_security_retirement: 12_000 # $1,000/month + ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: + # Income $1,000/mo; countable $980 after $20 exclusion; below 120% FPL + # $1,565/mo. SMME-ineligible; person gets regular SSI instead + # (FBR $967 - countable $980 < 0, so no federal SSI either). + ia_ssa_category: [NONE] ia_ssa_smme_supplement: [0] -- name: Case 3, person without Medicare Part B receives zero SMME. +- name: Case 3, aged Iowan without full Medicaid gets no SMME. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true - meets_ssi_resource_test: true - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: false + social_security_retirement: 24_000 + ia_ssa_has_full_medicaid: false + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] state_code: IA output: + ia_ssa_category: [NONE] ia_ssa_smme_supplement: [0] -- name: Case 4, aged Iowan with Medicaid and Part B integration (federal SSI plus SMME). +- name: Case 4, aged Iowan without Medicare Part B gets no SMME. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - employment_income: 0 + social_security_retirement: 24_000 ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: true + ia_ssa_has_medicare_part_b: false marital_units: marital_unit: members: [person1] @@ -76,24 +119,29 @@ members: [person1] state_code: IA output: - is_ssi_eligible: [true] - ia_ssa_eligible: [true] - ia_ssa_category: [SMME] - ssi: [967] - ia_ssa_smme_supplement: [1] - ia_ssa: [1] + ia_ssa_category: [NONE] + ia_ssa_smme_supplement: [0] - name: Case 5, person with excess resources receives zero SMME. period: 2025-01 + absolute_error_margin: 0.01 input: people: person1: age: 70 - is_ssi_aged_blind_disabled: true - is_ssi_eligible: true + social_security_retirement: 24_000 ssi_countable_resources: 5_000 ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] households: household: members: [person1] @@ -102,3 +150,62 @@ # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false ia_ssa_eligible: [false] ia_ssa_smme_supplement: [0] + +- name: Case 6, income exactly at 120% FPL boundary is not SMME-eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # $18,780/year gross = $1,565/month; countable = $1,545 after $20 + # exclusion, which is below the $1,565 threshold. Boundary check. + social_security_retirement: 18_780 + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Statute requires income to EXCEED 120% FPL (>, not >=). + ia_ssa_category: [NONE] + ia_ssa_smme_supplement: [0] + +- name: Case 7, aged Iowan at 2026 rates with income above 120% FPL. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # 2026 FPL (1 person, contiguous) = $15,960; 120% = $19,152/year. + social_security_retirement: 30_000 # $2,500/month, well above threshold + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_category: [SMME] + ia_ssa_smme_supplement: [1] + ia_ssa: [1] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py index b3f41f85f94..2cc6aca96fc 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py @@ -6,7 +6,6 @@ class ia_ssa_blind_supplement(Variable): entity = Person definition_period = MONTH label = "Iowa SSA blind supplement" - documentation = "Iowa SSA blind supplement. Per IAC 441—52.1(4), a blind recipient receives this supplement only if they are not receiving another type of state supplementary assistance; this is enforced via ia_ssa_category returning BLIND only when no higher-priority category applies." unit = USD defined_for = StateCode.IA reference = ( diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py index 60f540c7319..3832ff3d929 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py @@ -6,7 +6,6 @@ class ia_ssa_has_full_medicaid(Variable): entity = Person definition_period = MONTH label = "Iowa SSA receives full Medicaid" - documentation = "Whether the person receives full Medicaid without a spend down or premium, as required for Iowa SSA SMME category (IAC 441—51.7(1)). Defaults to federal medicaid_enrolled, which does not distinguish full vs partial coverage; override for spend-down recipients." defined_for = StateCode.IA reference = ( "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py index d11b9639327..a68567786a0 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py @@ -6,7 +6,6 @@ class ia_ssa_has_medicare_part_b(Variable): entity = Person definition_period = MONTH label = "Iowa SSA eligible for Medicare Part B" - documentation = "Whether the person is enrolled in Medicare Part B, as required for Iowa SSA SMME category (IAC 441—51.7(4)). Defaults to federal medicare_enrolled, which covers Part A and/or B; override for Part-A-only recipients." defined_for = StateCode.IA reference = ( "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py index ebf4a988321..1e4404e5c59 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py @@ -8,7 +8,7 @@ class ia_ssa_smme_eligible(Variable): label = "Iowa SSA SMME eligible" defined_for = StateCode.IA reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2", + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2", "https://www.legis.iowa.gov/docs/code/249.3.pdf", ) @@ -16,4 +16,16 @@ def formula(person, period, parameters): aged_or_disabled = person("is_ssi_aged_blind_disabled", period.this_year) has_medicaid = person("ia_ssa_has_full_medicaid", period) has_medicare = person("ia_ssa_has_medicare_part_b", period) - return aged_or_disabled & has_medicaid & has_medicare + # IAC 441—51.7(6): income must exceed 120% of the federal poverty + # level. SMME is a $1 technical SSP pathway for people categorically + # SSI-eligible but income-ineligible, so the FPL floor is what + # distinguishes them from regular SSI recipients. + p = parameters(period).gov.states.ia.hhs.ssa + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + fpg_monthly = person.spm_unit("spm_unit_fpg", period.this_year) / MONTHS_IN_YEAR + income_above_fpl_floor = ( + countable_monthly > p.smme.minimum_income_fpl_multiplier * fpg_monthly + ) + return aged_or_disabled & has_medicaid & has_medicare & income_above_fpl_floor diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py index d770f33bcea..d07445d9d8d 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py @@ -16,4 +16,4 @@ def formula(person, period, parameters): category = person("ia_ssa_category", period) in_category = category == category.possible_values.SMME p = parameters(period).gov.states.ia.hhs.ssa - return in_category * p.smme + return in_category * p.smme.amount From 77f8cf476efe9e56bf7780ce9f78da1697bee434 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 22 Apr 2026 13:33:26 -0400 Subject: [PATCH 07/23] Fix IHHRC couple cap, blind phase-out, Part B docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IHHRC (IAC 441—177.10(3) and 441—177.4(1)(f)): - Maximum benefit payable is $480.55 per person, always — not $961.10 per person when both need care. The $961.10 is the combined couple INCOME cap in 441—177.4(1)(f), not a payment cap. - Income eligibility now compares combined marital-unit countable income against $961.10 when both spouses need care, and individual countable income against $480.55 otherwise. - Updated parameter descriptions and tests; dropped the now-irrelevant 441—52.1(5) reference on max_cost_couple (that subsection defers to Chapter 177, which sets the per-person payment cap at $480.55). Blind (IAC 441—52.1(4)): - Applied federally-administered SSP V-shape formula (like DP/FLH): max(0, FBR + state_standard - max(countable, FBR)). A blind recipient with countable income above $989 now correctly phases to $0 instead of receiving a flat $22 regardless of income. Medicare Part B (IAC 441—51.7(4)): - Documented that PolicyEngine's medicare_enrolled does not distinguish Part A from Part B. SMME statutorily requires Part B; using medicare_enrolled as the closest proxy, acknowledging Part A-only enrollees are not filtered out. RCF eligibility PNA check reviewed and confirmed correct per statute: 441—51.4(3) compares "income according to 441—paragraph 52.1(3)(a)" which already incorporates the PNA as disregard (2) before the 31 × max_per_diem threshold test. No change needed. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia/hhs/ssa/ihhrc/max_cost_couple.yaml | 6 +- .../ia/hhs/ssa/ihhrc/max_cost_single.yaml | 6 +- .../ia/hhs/ssa/ia_ssa_blind_supplement.yaml | 58 +++++++++++++++++++ .../ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml | 57 +++++++++++++++--- .../ia/hhs/ssa/ia_ssa_blind_supplement.py | 12 +++- .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 13 +++-- .../hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py | 11 ++-- .../ssa/smme/ia_ssa_has_medicare_part_b.py | 7 +++ 8 files changed, 142 insertions(+), 28 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml index d57ec1a78a1..65673cc5b58 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml @@ -1,4 +1,4 @@ -description: Iowa limits the in-home health-related care supplement and countable income to this amount when both members of a couple need care under the State Supplementary Assistance program. +description: Iowa limits combined couple countable income to this amount when both spouses need in-home health-related care under the State Supplementary Assistance program. values: 2017-07-01: 961.10 @@ -6,9 +6,7 @@ values: metadata: unit: currency-USD period: month - label: Iowa SSA in-home health-related care maximum cost couple + label: Iowa SSA in-home health-related care combined couple income cap reference: - title: Iowa Administrative Code 441—177.4(1)(f) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2 - - title: Iowa Administrative Code 441—52.1(5) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml index b0ddf58aee5..9673adc7087 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml @@ -1,4 +1,4 @@ -description: Iowa limits the in-home health-related care supplement and countable income to this amount when one member of the household needs care under the State Supplementary Assistance program. +description: Iowa limits the in-home health-related care supplement and countable income to this amount per person under the State Supplementary Assistance program. values: 2017-07-01: 480.55 @@ -10,5 +10,5 @@ metadata: reference: - title: Iowa Administrative Code 441—177.4(1)(f) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2 - - title: Iowa Administrative Code 441—52.1(5) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 + - title: Iowa Administrative Code 441—177.10(3) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=4 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml index b1c315ff6ba..8c82f631a92 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml @@ -166,3 +166,61 @@ output: # Blind supplement frozen at $22 since 2017. ia_ssa_blind_supplement: [22] + +- name: Case 7, blind person with income above FBR plus state standard gets zero supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + social_security_retirement: 14_400 # $1,200/mo gross + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,200/mo SS gross -> $1,180/mo countable (after $20 disregard). + # FBR $967, blind state standard $22, total $989. + # Federally-administered formula: max(0, 989 - max(1180, 967)) = 0. + ia_ssa_category: [BLIND] + ia_ssa_blind_supplement: [0] + +- name: Case 8, blind person with income just above FBR gets partial supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + social_security_retirement: 12_000 # $1,000/mo gross + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,000/mo SS gross -> $980/mo countable (after $20 disregard). + # FBR $967, blind state standard $22, total $989. + # Federally-administered formula: max(0, 989 - max(980, 967)) = 9. + ia_ssa_category: [BLIND] + ia_ssa_blind_supplement: [9] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml index a52b0ff4aaf..d7a3e8e9730 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml @@ -1,7 +1,9 @@ -# IAC 441—177.4(1)(f): IHHRC supplement pays actual cost up to max_cost_single -# ($480.55) or max_cost_couple ($961.10) when both spouses need care. +# IAC 441—177.10(3): IHHRC max benefit payable is $480.55 per person, inclusive +# of all services for all providers. The $961.10 in 441—177.4(1)(f) is the +# combined couple income cap, NOT a per-person payment cap. # IAC 441—177.4(1)(c): recipient must live in own home (not in RCF or FLH). -# Income cap: countable monthly income <= max_cost_single/couple. +# IAC 441—177.4(1)(f): income cap — individual countable income <= $480.55, or +# combined couple countable income <= $961.10 when both spouses need care. - name: Case 1, individual IHHRC cost below max pays actual cost. period: 2025-01 @@ -139,11 +141,13 @@ members: [person1, person2] state_code: IA output: - # Both need care -> couple cap $961.10; each cost $900 < cap -> $900 each + # Both need care -> combined income cap $961.10 (combined countable = 0). + # Payment max is $480.55 per person (441—177.10(3)). + # Each cost $900 > per-person max $480.55 -> capped at $480.55 each. ia_ssa_ihhrc_both_need_care: [true, true] - ia_ssa_ihhrc_supplement: [900, 900] + ia_ssa_ihhrc_supplement: [480.55, 480.55] -- name: Case 6, couple both needing IHHRC above couple cap capped at 961.10 dollars. +- name: Case 6, couple both needing IHHRC with high cost capped at 480.55 dollars per person. period: 2025-01 absolute_error_margin: 0.01 input: @@ -172,8 +176,10 @@ members: [person1, person2] state_code: IA output: - # Both need care -> couple cap $961.10; each cost $1500 > cap -> capped - ia_ssa_ihhrc_supplement: [961.10, 961.10] + # Both need care -> combined income cap $961.10 (combined countable = 0). + # Payment max is $480.55 per person (441—177.10(3)). + # Each cost $1,500 > per-person max $480.55 -> capped at $480.55 each. + ia_ssa_ihhrc_supplement: [480.55, 480.55] - name: Case 7, couple with only one spouse needing IHHRC uses single cap. period: 2025-01 @@ -263,3 +269,38 @@ # $800/mo SS gross, countable $780/mo; below FBR $967, but IHHRC cap # compares countable $780 against $480.55 -> exceeds cap -> ineligible. ia_ssa_ihhrc_supplement: [0] + +- name: Case 10, couple both needing IHHRC uses combined couple income cap of 961.10 dollars. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 7_200 # $600/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + person2: + age: 68 + social_security_retirement: 7_200 # $600/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Each spouse's countable unearned is about $580/mo after $20 disregard, + # combined ~$1,160 which exceeds the couple income cap of $961.10. + # IAC 441—177.4(1)(f): both spouses fail the combined cap -> ineligible. + ia_ssa_ihhrc_both_need_care: [true, true] + ia_ssa_ihhrc_supplement: [0, 0] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py index 2cc6aca96fc..bcf967fefcb 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py @@ -16,4 +16,14 @@ def formula(person, period, parameters): category = person("ia_ssa_category", period) in_category = category == category.possible_values.BLIND p = parameters(period).gov.states.ia.hhs.ssa - return in_category * p.blind + # Iowa blind is federally-administered per POMS SI 01415.050.F. For + # federally-administered SSP, the state supplement equals + # max(0, total_standard − max(countable_income, FBR)): it stays at the + # full state amount while income is below the FBR and then phases down + # dollar-for-dollar as income rises above the FBR. + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + fbr = parameters(period).gov.ssa.ssi.amount.individual + raw_supplement = max_(0, (fbr + p.blind) - max_(countable_monthly, fbr)) + return in_category * raw_supplement diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py index 181dd2f6ea8..c8980181355 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py @@ -41,12 +41,15 @@ def formula(person, period, parameters): rcf_income_eligible = client_participation < rcf_income_threshold needs_ihhrc = person("ia_ssa_needs_in_home_health_related_care", period) both_need_care = person("ia_ssa_ihhrc_both_need_care", period) - ihhrc_income_cap = where( - both_need_care, p.ihhrc.max_cost_couple, p.ihhrc.max_cost_single + # IAC 441—177.4(1)(f): countable income of the individual and spouse + # living in the home shall be limited to $480.55 per month if one needs + # care or $961.10 (combined) if both need care. + couple_countable = person.marital_unit.sum(countable_monthly) + ihhrc_income_eligible = where( + both_need_care, + couple_countable <= p.ihhrc.max_cost_couple, + countable_monthly <= p.ihhrc.max_cost_single, ) - # IAC 441—177.4(1)(f): cap is compared against the person's monthly - # countable income, not the excess over the federal SSI benefit rate. - ihhrc_income_eligible = countable_monthly <= ihhrc_income_cap in_flh = person("ia_ssa_resides_in_family_life_home", period) # IAC 441—177.4(1)(c): IHHRC recipients must live in their own home, # so exclude those residing in an RCF or family-life home. diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py index 74c881f3700..37227041e4b 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py @@ -17,10 +17,7 @@ def formula(person, period, parameters): in_category = category == category.possible_values.IHHRC p = parameters(period).gov.states.ia.hhs.ssa cost = person("ia_ssa_ihhrc_cost_of_care", period) - both_need_care = person("ia_ssa_ihhrc_both_need_care", period) - max_cost = where( - both_need_care, - p.ihhrc.max_cost_couple, - p.ihhrc.max_cost_single, - ) - return in_category * min_(cost, max_cost) + # IAC 441—177.10(3): maximum benefit payable is $480.55 per client, + # inclusive of all services for all providers. The $961.10 is the + # combined couple income cap in IAC 441—177.4(1)(f), not a payment cap. + return in_category * min_(cost, p.ihhrc.max_cost_single) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py index a68567786a0..30f849407c5 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py @@ -12,4 +12,11 @@ class ia_ssa_has_medicare_part_b(Variable): ) def formula(person, period, parameters): + # IAC 441—51.7(4) requires SMME recipients to be currently eligible for + # Medicare Part B. PolicyEngine's medicare_enrolled does not distinguish + # Part A from Part B, so this uses it as the closest proxy — accepting + # that Part A-only enrollees are not filtered out. In practice, the + # SMME target population is dual-eligibles whose Part B premiums are + # paid by Medicaid, so enrollment in Medicare correlates strongly with + # Part B enrollment. return person("medicare_enrolled", period.this_year) From ec32b3ff0132396e48dc5eadf50db518d06f3f58 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 22 Apr 2026 13:44:40 -0400 Subject: [PATCH 08/23] Tighten blind gate and Part B input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Blind (IAC 441—52.1(4)): - Added income gate to BLIND category assignment that matches the federally-administered V-shape ceiling (FBR + state standard = $989). A blind person whose countable income exceeds $989 now falls through to the next applicable category (e.g., SMME if income is also above 120% FPL) rather than being labeled BLIND with a $0 supplement. Medicare Part B (IAC 441—51.7(4)): - Converted ia_ssa_has_medicare_part_b to a pure input variable with default False. Previously the formula defaulted to medicare_enrolled (Part A and/or B), which pulled Part A-only enrollees into SMME. SMME is a $1/month program for a narrow dual-eligible population; a False default with explicit opt-in matches both the statutory requirement ("currently eligible for Medicare Part B") and the real caseload better than an overbroad proxy. RCF eligibility PNA check re-verified: IAC 441—51.4(3) references "the income according to 441—paragraph 52.1(3)(a)," and 52.1(3)(a) defines "Income applied to meet the cost of care" as (countable + SSI benefit) minus five disregards including the PNA (disregard 2). The current code applies the PNA as the statute directs. No change. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml | 7 ++++--- .../gov/states/ia/hhs/ssa/ia_ssa_category.yaml | 11 +++++++---- .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 8 +++++++- .../ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py | 11 +---------- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml index 8c82f631a92..a72cc5f3689 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml @@ -191,9 +191,10 @@ state_code: IA output: # $1,200/mo SS gross -> $1,180/mo countable (after $20 disregard). - # FBR $967, blind state standard $22, total $989. - # Federally-administered formula: max(0, 989 - max(1180, 967)) = 0. - ia_ssa_category: [BLIND] + # FBR $967, blind state standard $22, total $989. Countable $1,180 + # exceeds $989 -> blind income gate in ia_ssa_category excludes, so + # category drops to NONE and supplement is $0. + ia_ssa_category: [NONE] ia_ssa_blind_supplement: [0] - name: Case 8, blind person with income just above FBR gets partial supplement. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml index 7e5e5ee5add..bd63cf803be 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml @@ -223,7 +223,7 @@ # DP outranks BLIND ia_ssa_category: [DP] -- name: Case 9, blind person with SMME-eligible income gets BLIND not SMME. +- name: Case 9, blind person with SMME-range income falls to SMME not BLIND. period: 2025-01 absolute_error_margin: 0.01 input: @@ -231,7 +231,7 @@ person1: age: 70 is_blind: true - social_security_retirement: 24_000 # > 120% FPL + social_security_retirement: 24_000 # $2,000/mo -> countable $1,980 ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true marital_units: @@ -248,8 +248,11 @@ members: [person1] state_code: IA output: - # BLIND outranks SMME - ia_ssa_category: [BLIND] + # Blind income gate (FBR $967 + $22 = $989). Countable $1,980 > $989 -> + # BLIND branch skipped. SMME income floor is 120% FPL ($1,565); $1,980 > + # $1,565 -> SMME applies. BLIND and SMME income ranges are disjoint, so + # priority ordering between them is academic. + ia_ssa_category: [SMME] - name: Case 10, DP-configured person with SMME-eligible income gets DP not SMME. period: 2025-01 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py index c8980181355..ea025c3f04b 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py @@ -58,6 +58,12 @@ def formula(person, period, parameters): dp_configuration = person("ia_ssa_dp_configuration", period) in_dp = dp_configuration != dp_configuration.possible_values.NONE is_blind = person("is_blind", period.this_year) + # IAC 441—52.1(4) blind standard is a federally-administered SSP; + # supplement phases to zero when countable income reaches FBR + + # state standard. Mirror that ceiling in the category gate so blind + # recipients with excess income fall through to the next category. + fbr = parameters(period).gov.ssa.ssi.amount.individual + blind_income_eligible = countable_monthly < fbr + p.blind smme_eligible = person("ia_ssa_smme_eligible", period) return select( [ @@ -65,7 +71,7 @@ def formula(person, period, parameters): eligible & needs_ihhrc & in_own_home & ihhrc_income_eligible, eligible & in_flh, eligible & has_dependent & in_dp, - eligible & is_blind, + eligible & is_blind & blind_income_eligible, eligible & smme_eligible, ], [ diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py index 30f849407c5..de2d24cb551 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_medicare_part_b.py @@ -7,16 +7,7 @@ class ia_ssa_has_medicare_part_b(Variable): definition_period = MONTH label = "Iowa SSA eligible for Medicare Part B" defined_for = StateCode.IA + default_value = False reference = ( "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" ) - - def formula(person, period, parameters): - # IAC 441—51.7(4) requires SMME recipients to be currently eligible for - # Medicare Part B. PolicyEngine's medicare_enrolled does not distinguish - # Part A from Part B, so this uses it as the closest proxy — accepting - # that Part A-only enrollees are not filtered out. In practice, the - # SMME target population is dual-eligibles whose Part B premiums are - # paid by Medicaid, so enrollment in Medicare correlates strongly with - # Part B enrollment. - return person("medicare_enrolled", period.this_year) From 9d19e76e64d67949e53f18da98c12fbb9d6ba8e2 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 22 Apr 2026 21:51:30 -0400 Subject: [PATCH 09/23] Use gross income for RCF eligibility gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IAC 441—51.4(3) compares "the income according to 441—paragraph 52.1(3)(a)" against 31 × max_per_diem. Section 52.1(3)(a) describes two concepts: the gross income input (SSI countable + SSI benefit) and the post-disregard "Income applied to meet the cost of care" (client participation). The statute is textually ambiguous as to which "the income" refers to, but: - 31 × max_per_diem is approximately the monthly cost of RCF care at the maximum per-diem rate. Comparing gross monthly income against that cost is the meaningful substantive test — it excludes people who could afford care on their own income. - Standard benefit-program convention uses gross income for eligibility tests, with disregards (including personal needs allowances) applied in the benefit amount calculation. - Under the post-disregard reading, the test barely screens anyone out: income must exceed ~$1,292 (threshold + PNA + other disregards) to be ineligible at the 2025 per-diem rate, so the eligibility gate had almost no substantive effect. Switched ia_ssa_category.py to compare total_rcf_income (pre-PNA) against 31 × max_per_diem. The PNA remains in ia_ssa_rcf_supplement where it belongs: reducing client participation in the payment calculation. Cross-verified against SSA POMS SI 01415.050.F: RCF is state- administered by Iowa HHS, so this is a state policy interpretation, not a federal SSP formula question. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py index ea025c3f04b..9ad772b40b4 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py @@ -30,15 +30,15 @@ def formula(person, period, parameters): person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR ) ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR - # Iowa-administered RCF client participation uses total monthly income - # (SSI countable + federal SSI payment), not the |FBR − income| V-shape. + # IAC 441—51.4(3): RCF income eligibility compares gross monthly income + # (SSI countable + federal SSI payment, before disregards) against 31 × + # max_per_diem. Disregards including the personal needs allowance + # affect only the payment calculation in ia_ssa_rcf_supplement, not + # the eligibility gate here. total_rcf_income = countable_monthly + ssi_monthly in_rcf = person("ia_ssa_resides_in_residential_care_facility", period) - client_participation = max_( - 0, total_rcf_income - p.rcf.personal_needs_allowance - ) rcf_income_threshold = p.rcf.days_multiplier * p.rcf.max_per_diem - rcf_income_eligible = client_participation < rcf_income_threshold + rcf_income_eligible = total_rcf_income < rcf_income_threshold needs_ihhrc = person("ia_ssa_needs_in_home_health_related_care", period) both_need_care = person("ia_ssa_ihhrc_both_need_care", period) # IAC 441—177.4(1)(f): countable income of the individual and spouse From 65eb01d3c2623fce76004746cefc4c727157f256 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 22 Apr 2026 22:15:53 -0400 Subject: [PATCH 10/23] Backdate Iowa SSA parameters with authoritative historical sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prior "2017-07-01" effective date was incorrect — those values were copied from Iowa HHS's current web page (which shows 2025 values) and backdated to 2017 without historical verification. Replaced with properly sourced historical tiers: - **2011-01-01**: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1. Provides frozen values ($22 blind, $142 FLH aged max supplement, $480.55 / $961.10 IHHRC) and 2011 baselines for COLA-adjusted parameters. - **2017-01-01**: Iowa Administrative Code 01-04-2017 supplement. Provides 441—52.1 dollar amounts (FLH $897, DP $1,114/$1,482/$1,136/ $1,504/$1,526, RCF per diem $30.11, PNA $100) and 441—51.4(1) dependent-relative income limit $379. - **2018-01-01**: Iowa Administrative Code 03-28-2018 rule update for 441—52.1. Provides 2018 COLA values (FLH $912, DP $1,137/$1,512/ $1,159/$1,534/$1,556, RCF per diem $30.60, PNA $99). - **2025-01-01**: Iowa HHS General Letter 6-B-46 (effective January 1, 2025). Corresponds to the values previously misdated 2017-07-01. Preserves test expectations at 2025-01 period. - **2026-01-01**: Iowa HHS current State Supplementary Assistance Standards web page (unchanged). SMME parameters (amount $1, 120% FPL multiplier) start at 2017-01-01 — the program existed since October 1, 2003 but the SSA 2011 report does not publish the $1 amount directly, so we cite only what we can verify. DP dependent_income_limit and max_per_person_cap start at 2017-01-01 because the SSA 2011 report does not publish these specific Iowa-only concepts; the 2017 IAC supplement is the earliest direct source. All 73 Iowa SSA tests continue to pass at 2025-01 and 2026-01 periods. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../gov/states/ia/hhs/ssa/blind.yaml | 10 +++-- .../ia/hhs/ssa/dp/assistance_standard.yaml | 42 +++++++++++++++---- .../ia/hhs/ssa/dp/dependent_income_limit.yaml | 9 +++- .../ia/hhs/ssa/dp/max_per_person_cap.yaml | 9 +++- .../ia/hhs/ssa/flh/assistance_standard.yaml | 15 ++++++- .../states/ia/hhs/ssa/flh/max_supplement.yaml | 6 +-- .../ia/hhs/ssa/ihhrc/max_cost_couple.yaml | 4 +- .../ia/hhs/ssa/ihhrc/max_cost_single.yaml | 4 +- .../ia/hhs/ssa/rcf/days_multiplier.yaml | 4 +- .../states/ia/hhs/ssa/rcf/max_per_diem.yaml | 15 ++++++- .../hhs/ssa/rcf/personal_needs_allowance.yaml | 15 ++++++- .../gov/states/ia/hhs/ssa/smme/amount.yaml | 8 ++-- .../smme/minimum_income_fpl_multiplier.yaml | 4 +- 13 files changed, 114 insertions(+), 31 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml index 044c3149ee0..56e9f101d1e 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind.yaml @@ -1,7 +1,7 @@ description: Iowa provides this amount as the blind supplement under the State Supplementary Assistance program. values: - 2017-07-01: 22 + 2011-01-01: 22 metadata: unit: currency-USD @@ -10,5 +10,9 @@ metadata: reference: - title: Iowa Administrative Code 441—52.1(4) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 - - title: Iowa HHS State Supplementary Assistance Standards - href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 + - title: Iowa Administrative Code 441—52.1(4), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=120 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml index 951c5d8b897..e2b3bdb3d34 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml @@ -9,24 +9,50 @@ metadata: reference: - title: Iowa Administrative Code 441—52.1(2) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa HHS State Supplementary Assistance Standards + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 OS code C totals + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 + - title: Iowa Administrative Code 441—52.1(2), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=119 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 + - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) + href: https://hhs.iowa.gov/media/15607/download + - title: Iowa HHS State Supplementary Assistance Standards (current) href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance AGED_OR_DISABLED_WITH_DEPENDENT: - 2017-07-01: 1_470 + 2011-01-01: 1_018 + 2017-01-01: 1_114 + 2018-01-01: 1_137 + 2025-01-01: 1_470 2026-01-01: 1_512 AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT: - 2017-07-01: 1_953 + 2011-01-01: 1_355 + 2017-01-01: 1_482 + 2018-01-01: 1_512 + 2025-01-01: 1_953 2026-01-01: 2_009 BLIND_WITH_DEPENDENT: - 2017-07-01: 1_492 + 2011-01-01: 1_040 + 2017-01-01: 1_136 + 2018-01-01: 1_159 + 2025-01-01: 1_492 2026-01-01: 1_534 BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: - 2017-07-01: 1_975 - # Verified against Iowa HHS SSA payment standards page (hhs.iowa.gov/assistance-programs/state-supplementary-assistance): the 2026 value is $3,031, a ~53% jump over the 2017 baseline. Anomalous vs other configurations' ~2.85% COLA but published as stated. + # 2011: SSA Table 1 shows both-blind couple $1,399; footnote a reduces by $22 + # when only one member is blind, giving $1,377. + 2011-01-01: 1_377 + 2017-01-01: 1_504 + 2018-01-01: 1_534 + 2025-01-01: 1_975 + # Iowa HHS published 2026 value is $3,031, a ~53% jump over 2025 $1,975 — + # anomalous vs other configurations' ~2.85% COLA but published as stated. 2026-01-01: 3_031 BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT: - 2017-07-01: 1_997 + 2011-01-01: 1_399 + 2017-01-01: 1_526 + 2018-01-01: 1_556 + 2025-01-01: 1_997 2026-01-01: 2_053 NONE: - 2017-07-01: 0 + 2011-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml index 72fac83478a..a02f7021ff5 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml @@ -1,7 +1,8 @@ description: Iowa limits a dependent relative's countable income to this amount for dependent person eligibility under the State Supplementary Assistance program. values: - 2017-07-01: 503 + 2017-01-01: 379 + 2025-01-01: 503 2026-01-01: 518 metadata: @@ -9,7 +10,11 @@ metadata: period: month label: Iowa SSA dependent person dependent income limit reference: + - title: Iowa Administrative Code 441—51.4(1), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 - title: Iowa Administrative Code 441—52.1(2) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa HHS State Supplementary Assistance Standards + - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) + href: https://hhs.iowa.gov/media/15607/download + - title: Iowa HHS State Supplementary Assistance Standards (current) href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml index fd23198c126..da45a2ee1e3 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml @@ -1,7 +1,8 @@ description: Iowa limits the dependent person supplement to this amount per eligible person under the State Supplementary Assistance program. values: - 2017-07-01: 503 + 2017-01-01: 379 + 2025-01-01: 503 2026-01-01: 518 metadata: @@ -9,7 +10,11 @@ metadata: period: month label: Iowa SSA dependent person maximum payment per person reference: + - title: Iowa Administrative Code 441—51.4(1), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 - title: Iowa Administrative Code 441—52.1(2) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa HHS State Supplementary Assistance Standards + - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) + href: https://hhs.iowa.gov/media/15607/download + - title: Iowa HHS State Supplementary Assistance Standards (current) href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml index bfc5624872f..4a6c884eb1a 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml @@ -1,7 +1,10 @@ description: Iowa provides this amount as the family-life home assistance standard under the State Supplementary Assistance program. values: - 2017-07-01: 1_129 + 2011-01-01: 816 + 2017-01-01: 897 + 2018-01-01: 912 + 2025-01-01: 1_129 2026-01-01: 1_156 metadata: @@ -11,5 +14,13 @@ metadata: reference: - title: Iowa Administrative Code 441—52.1(1) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa HHS State Supplementary Assistance Standards + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 OS code D aged total + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 + - title: Iowa Administrative Code 441—52.1(1), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=119 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 + - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) + href: https://hhs.iowa.gov/media/15607/download + - title: Iowa HHS State Supplementary Assistance Standards (current) href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml index 855050dde3e..1f9ec6b3c30 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml @@ -1,7 +1,7 @@ description: Iowa limits the family-life home supplement to this amount under the State Supplementary Assistance program. values: - 2017-07-01: 142 + 2011-01-01: 142 metadata: unit: currency-USD @@ -10,5 +10,5 @@ metadata: reference: - title: Iowa Administrative Code 441—52.1(1) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa HHS State Supplementary Assistance Standards - href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 OS code D aged + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml index 65673cc5b58..925eb82eebd 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_couple.yaml @@ -1,7 +1,7 @@ description: Iowa limits combined couple countable income to this amount when both spouses need in-home health-related care under the State Supplementary Assistance program. values: - 2017-07-01: 961.10 + 2011-01-01: 961.10 metadata: unit: currency-USD @@ -10,3 +10,5 @@ metadata: reference: - title: Iowa Administrative Code 441—177.4(1)(f) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2 + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 in-home health care couple + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml index 9673adc7087..c474a5ce287 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml @@ -1,7 +1,7 @@ description: Iowa limits the in-home health-related care supplement and countable income to this amount per person under the State Supplementary Assistance program. values: - 2017-07-01: 480.55 + 2011-01-01: 480.55 metadata: unit: currency-USD @@ -12,3 +12,5 @@ metadata: href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2 - title: Iowa Administrative Code 441—177.10(3) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=4 + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 in-home health care + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml index 7a3bd185ff9..e8b10eb804d 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml @@ -1,7 +1,7 @@ description: Iowa uses this number of days per month to convert the maximum per diem to a monthly residential care income limit under the State Supplementary Assistance program. values: - 2017-07-01: 31 + 2011-01-01: 31 metadata: unit: day @@ -12,3 +12,5 @@ metadata: href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf - title: Iowa Administrative Code 441—52.1(3) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 + - title: Iowa Administrative Code 441—51.3(3), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/max_per_diem.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/max_per_diem.yaml index e02b2623c69..5475be42ee6 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/max_per_diem.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/max_per_diem.yaml @@ -1,7 +1,10 @@ description: Iowa provides this amount as the maximum cost-related per diem for residential care facility residents under the State Supplementary Assistance program. values: - 2017-07-01: 37.60 + 2011-01-01: 28.14 + 2017-01-01: 30.11 + 2018-01-01: 30.60 + 2025-01-01: 37.60 2026-01-01: 38.47 metadata: @@ -11,5 +14,13 @@ metadata: reference: - title: Iowa Administrative Code 441—52.1(3) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa HHS State Supplementary Assistance Standards + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 footnote b + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 + - title: Iowa Administrative Code 441—52.1(3), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=119 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 + - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) + href: https://hhs.iowa.gov/media/15607/download + - title: Iowa HHS State Supplementary Assistance Standards (current) href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/personal_needs_allowance.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/personal_needs_allowance.yaml index 79f5b3e97d7..5e3af7c9ced 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/personal_needs_allowance.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/personal_needs_allowance.yaml @@ -1,7 +1,10 @@ description: Iowa provides this amount as the residential care facility personal needs allowance under the State Supplementary Assistance program. values: - 2017-07-01: 126 + 2011-01-01: 93 + 2017-01-01: 100 + 2018-01-01: 99 + 2025-01-01: 126 2026-01-01: 130 metadata: @@ -13,5 +16,13 @@ metadata: href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - title: Iowa Code Section 249.9A href: https://www.legis.iowa.gov/docs/code/249.9A.pdf - - title: Iowa HHS State Supplementary Assistance Standards + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 footnote b + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 + - title: Iowa Administrative Code 441—52.1(3), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=119 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 + - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) + href: https://hhs.iowa.gov/media/15607/download + - title: Iowa HHS State Supplementary Assistance Standards (current) href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml index 6d7efd04a40..1cbb2a2574c 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml @@ -1,7 +1,7 @@ description: Iowa provides this amount as the supplement for Medicare and Medicaid eligibles under the State Supplementary Assistance program. values: - 2017-07-01: 1 + 2017-01-01: 1 metadata: unit: currency-USD @@ -10,5 +10,7 @@ metadata: reference: - title: Iowa Administrative Code 441—52.1(7) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 - - title: Iowa HHS State Supplementary Assistance Standards - href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance + - title: Iowa Administrative Code 441—52.1(7), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=120 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=3 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml index 9296a4983ee..f5ced35272d 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml @@ -1,7 +1,7 @@ description: Iowa uses this share of the federal poverty level as the minimum income threshold for supplement for Medicare and Medicaid eligibles under the State Supplementary Assistance program. values: - 2017-07-01: 1.2 + 2017-01-01: 1.2 metadata: unit: /1 @@ -10,3 +10,5 @@ metadata: reference: - title: Iowa Administrative Code 441—51.7(6) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 + - title: Iowa Administrative Code 441—51.6(6), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=114 From 1420e7da10f1637014b4e8bf081f1ac2cd4a8d75 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 22 Apr 2026 23:47:49 -0400 Subject: [PATCH 11/23] Apply Iowa SSA review fixes and per-IAC participation math - RCF income gate now compares post-PNA client participation against 31 x max_per_diem per IAC 441-51.3(3) cross-ref to 52.1(3)"a" - IHHRC income gate applies the SSI FBR disregard and checks combined marital-unit countable against the applicable cap symmetrically - IHHRC payment subtracts client participation per IAC 441-177.10(2)(a), split evenly across marital-unit members - DP dependent-income-eligible check moved into ia_ssa_category so a person with a disqualifying dependent falls through to BLIND / SMME instead of receiving a zero DP supplement - Resource test sums marital-unit resources for joint SSI claims - ia_ssa_has_full_medicaid converted to an explicit input with default_value=False, matching ia_ssa_has_medicare_part_b, so Medicaid pathways outside "full Medicaid" (spenddown, MEPD premium) do not trigger SMME - Fix citation typos: SMME minimum_income_fpl_multiplier cites 441-51.6(6); RCF days_multiplier cites 441-51.3(3) with unit /1 and period eternity - Strengthen 2026 DP BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT comment documenting the +53.5% jump vs 2.85% COLA anomaly - Add 2017 DP and 2018 RCF historical test cases; add DP fallthrough category test; update IHHRC and resources tests for new rules; remove obsolete sources/working_references.md Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia/hhs/ssa/dp/assistance_standard.yaml | 8 +- .../ia/hhs/ssa/rcf/days_multiplier.yaml | 8 +- .../smme/minimum_income_fpl_multiplier.yaml | 2 +- .../states/ia/hhs/ssa/ia_ssa_category.yaml | 34 +- .../ia/hhs/ssa/ia_ssa_dp_supplement.yaml | 36 +- .../ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml | 70 +++- .../ia/hhs/ssa/ia_ssa_rcf_supplement.yaml | 33 +- .../ia/hhs/ssa/ia_ssa_resources_eligible.yaml | 22 +- .../ia/hhs/ssa/dp/ia_ssa_dp_supplement.py | 4 +- .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 53 ++- .../ia/hhs/ssa/ia_ssa_resources_eligible.py | 13 +- .../hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py | 25 +- .../hhs/ssa/smme/ia_ssa_has_full_medicaid.py | 10 +- sources/working_references.md | 366 ------------------ 14 files changed, 259 insertions(+), 425 deletions(-) delete mode 100644 sources/working_references.md diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml index e2b3bdb3d34..f07c823a37f 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml @@ -45,8 +45,12 @@ BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: 2017-01-01: 1_504 2018-01-01: 1_534 2025-01-01: 1_975 - # Iowa HHS published 2026 value is $3,031, a ~53% jump over 2025 $1,975 — - # anomalous vs other configurations' ~2.85% COLA but published as stated. + # 2026 value $3,031 as published on the Iowa HHS SSA standards page is a + # +53.5% jump vs 2025 ($1,975), out of step with the ~2.85% COLA applied to + # every other DP configuration. An expected ~$2,031 would match that COLA, + # so $3,031 may reflect an Iowa HHS publication error. Encoded as published; + # pending confirmation from Iowa HHS. If Iowa HHS corrects the figure, + # update here. 2026-01-01: 3_031 BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT: 2011-01-01: 1_399 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml index e8b10eb804d..41e111098cb 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml @@ -4,12 +4,12 @@ values: 2011-01-01: 31 metadata: - unit: day - period: year + unit: /1 + period: eternity label: Iowa SSA residential care facility days-per-month multiplier reference: - - title: Iowa Administrative Code 441—51.4 - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf + - title: Iowa Administrative Code 441—51.3(3) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 - title: Iowa Administrative Code 441—52.1(3) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 - title: Iowa Administrative Code 441—51.3(3), January 4, 2017 supplement diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml index f5ced35272d..004f643af7f 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml @@ -8,7 +8,7 @@ metadata: period: year label: Iowa SSA SMME minimum income FPL multiplier reference: - - title: Iowa Administrative Code 441—51.7(6) + - title: Iowa Administrative Code 441—51.6(6) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 - title: Iowa Administrative Code 441—51.6(6), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=114 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml index bd63cf803be..5f59bf5ca34 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml @@ -1,7 +1,7 @@ # Verifies ia_ssa_category priority ordering: # RCF > IHHRC > FLH > DP > BLIND > SMME > NONE # -# Note: SMME requires income > 120% FPL (IAC 441—51.7(6)). 2025 FPL 1-person +# Note: SMME requires income > 120% FPL (IAC 441—51.6(6)). 2025 FPL 1-person # (contiguous US) = $15,650; 120% = $18,780/year or $1,565/month. - name: Case 1, RCF resident who is also blind gets RCF category not BLIND. @@ -316,3 +316,35 @@ # IHHRC outranks SMME (SMME not active here — income $0 below 120% FPL — # but the priority order still applies even if SMME were active). ia_ssa_category: [IHHRC] + +- name: Case 12, blind person with DP configuration and over-income dependent falls to BLIND. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + is_blind: true + employment_income: 0 + ia_ssa_dp_configuration: BLIND_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 600 # > $503 2025 limit + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Dependent income $600 exceeds the $503 2025 dependent income limit, so + # the DP category gate fails. Person is blind with $0 countable (< FBR + + # blind standard) -> falls through to BLIND category. + ia_ssa_category: [BLIND] + ia_ssa_dp_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml index 36bed229ba3..41c22be146a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml @@ -177,9 +177,43 @@ members: [person1] state_code: IA output: + # Dependent income exceeds the limit -> DP category gate fails. Person + # is 70 with no other qualifying category -> NONE -> supplement 0. + ia_ssa_category: [NONE] ia_ssa_dp_supplement: [0] -- name: Case 7, DP supplement phases down when countable income exceeds FBR. +- name: Case 7, 2017 DP aged-or-disabled-with-dependent uses 1114 dollar standard and 379 dollar cap. + period: 2017-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # 2017 AGED_OR_DISABLED_WITH_DEPENDENT payment standard $1,114; FBR $735; + # max_per_person_cap $379. Federally-administered formula: + # max(0, 1114 - max(0, 735)) = $379 -> capped at $379. + ia_ssa_category: [DP] + ia_ssa_dp_supplement: [379] + +- name: Case 8, DP supplement phases down when countable income exceeds FBR. period: 2025-01 absolute_error_margin: 0.01 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml index d7a3e8e9730..7c5ec01f6d1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml @@ -1,9 +1,14 @@ +# IAC 441—177.10(2)(a): payment = max(0, min(cost, per-person cap) - +# client participation), where client participation is marital-unit +# countable income minus the basic SSI standard disregard (the applicable +# FBR for a single or joint claim), split evenly across the marital unit. # IAC 441—177.10(3): IHHRC max benefit payable is $480.55 per person, inclusive -# of all services for all providers. The $961.10 in 441—177.4(1)(f) is the -# combined couple income cap, NOT a per-person payment cap. +# of all services for all providers. The $961.10 in 441—177.4(1)(f) is the +# combined couple income cap, NOT a per-person payment cap. # IAC 441—177.4(1)(c): recipient must live in own home (not in RCF or FLH). -# IAC 441—177.4(1)(f): income cap — individual countable income <= $480.55, or -# combined couple countable income <= $961.10 when both spouses need care. +# IAC 441—177.4(1)(f): income cap on countable income after the basic SSI +# standard disregard — individual <= $480.55, or combined couple <= $961.10 +# when both spouses need care. - name: Case 1, individual IHHRC cost below max pays actual cost. period: 2025-01 @@ -238,11 +243,11 @@ members: [person1] state_code: IA output: - # Countable $1,647/mo exceeds single income cap $480.55 - # -> not in IHHRC category -> no supplement + # Countable $1,647/mo minus individual FBR disregard $967 = $680, which + # exceeds the single cap $480.55 -> not in IHHRC category -> no supplement. ia_ssa_ihhrc_supplement: [0] -- name: Case 9, IHHRC income cap enforced against countable income even below FBR. +- name: Case 9, single person with countable income below FBR gets full supplement. period: 2025-01 absolute_error_margin: 0.01 input: @@ -266,11 +271,12 @@ members: [person1] state_code: IA output: - # $800/mo SS gross, countable $780/mo; below FBR $967, but IHHRC cap - # compares countable $780 against $480.55 -> exceeds cap -> ineligible. - ia_ssa_ihhrc_supplement: [0] + # $800/mo SS gross, countable $780/mo. Individual FBR disregard $967 makes + # income after disregard 0 -> passes single cap. Client participation is + # 0 -> supplement equals cost $400. + ia_ssa_ihhrc_supplement: [400] -- name: Case 10, couple both needing IHHRC uses combined couple income cap of 961.10 dollars. +- name: Case 10, couple both needing IHHRC with combined countable below couple FBR. period: 2025-01 absolute_error_margin: 0.01 input: @@ -299,8 +305,44 @@ members: [person1, person2] state_code: IA output: - # Each spouse's countable unearned is about $580/mo after $20 disregard, - # combined ~$1,160 which exceeds the couple income cap of $961.10. - # IAC 441—177.4(1)(f): both spouses fail the combined cap -> ineligible. + # Each spouse's countable unearned is about $580/mo after the $20 general + # disregard, combined ~$1,160. Couple FBR disregard $1,450 leaves 0 after + # disregard -> passes couple cap $961.10. Client participation is 0 -> + # each person's supplement equals cost $400. + ia_ssa_ihhrc_both_need_care: [true, true] + ia_ssa_ihhrc_supplement: [400, 400] + +- name: Case 11, couple both needing IHHRC with combined countable above couple cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 15_840 # $1,320/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + person2: + age: 68 + social_security_retirement: 15_840 # $1,320/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Each spouse's countable ~$1,300/mo; combined ~$2,600. After couple FBR + # disregard $1,450 -> $1,150 countable, which exceeds the couple cap + # $961.10 -> both ineligible. ia_ssa_ihhrc_both_need_care: [true, true] ia_ssa_ihhrc_supplement: [0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml index c9217c83709..a877781aaa4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml @@ -202,7 +202,38 @@ # 31 * $37.60 income limit -> not in RCF category -> no supplement ia_ssa_rcf_supplement: [0] -- name: Case 8, RCF resident with excess resources receives zero supplement. +- name: Case 8, 2018 RCF resident uses the 99 dollar PNA effective March 2018. + period: 2018-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 30.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills to 2018 FBR $750. 2018 RCF: max_per_diem $30.60, + # PNA $99 (per March 28, 2018 IAC rule update). CP $750 - $99 = $651. + # Cost of care 31 * $30.60 = $948.60. Supplement $948.60 - $651 = $297.60. + ssi: [750] + ia_ssa_category: [RCF] + ia_ssa_rcf_supplement: [297.60] + +- name: Case 9, RCF resident with excess resources receives zero supplement. period: 2025-01 input: people: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml index 494fe8f9bbe..7b268ed42bf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml @@ -43,40 +43,50 @@ output: ia_ssa_resources_eligible: [true] -- name: Case 4, joint SSI couple at 3,000 limit is eligible. +- name: Case 4, joint SSI couple at combined 3,000 dollar limit is eligible. period: 2025-01 input: people: person1: age: 70 - ssi_countable_resources: 3_000 + ssi_countable_resources: 1_500 ssi_claim_is_joint: true person2: age: 68 - ssi_countable_resources: 3_000 + ssi_countable_resources: 1_500 ssi_claim_is_joint: true + marital_units: + marital_unit: + members: [person1, person2] households: household: members: [person1, person2] state_code: IA output: + # Federal SSI counts couple resources against the couple limit. Combined + # $3,000 equals the limit -> both eligible. ia_ssa_resources_eligible: [true, true] -- name: Case 5, joint SSI couple 1 dollar above 3,000 limit is ineligible. +- name: Case 5, joint SSI couple with 2,000 dollars each (combined 4,000 dollars) is ineligible. period: 2025-01 input: people: person1: age: 70 - ssi_countable_resources: 3_001 + ssi_countable_resources: 2_000 ssi_claim_is_joint: true person2: age: 68 - ssi_countable_resources: 3_001 + ssi_countable_resources: 2_000 ssi_claim_is_joint: true + marital_units: + marital_unit: + members: [person1, person2] households: household: members: [person1, person2] state_code: IA output: + # Combined $4,000 exceeds the couple limit $3,000 -> both ineligible, even + # though each individual is below the single limit. ia_ssa_resources_eligible: [false, false] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py index 898720739fa..d0fb4e808e6 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py @@ -30,6 +30,4 @@ def formula(person, period, parameters): fbr = parameters(period).gov.ssa.ssi.amount.individual raw_supplement = max_(0, payment_standard - max_(countable_monthly, fbr)) capped_supplement = min_(raw_supplement, p.dp.max_per_person_cap) - dependent_income = person("ia_ssa_dp_dependent_countable_income", period) - dependent_income_eligible = dependent_income < p.dp.dependent_income_limit - return in_category * dependent_income_eligible * capped_supplement + return in_category * capped_supplement diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py index 9ad772b40b4..5de9b84c0d6 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py @@ -30,26 +30,40 @@ def formula(person, period, parameters): person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR ) ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR - # IAC 441—51.4(3): RCF income eligibility compares gross monthly income - # (SSI countable + federal SSI payment, before disregards) against 31 × - # max_per_diem. Disregards including the personal needs allowance - # affect only the payment calculation in ia_ssa_rcf_supplement, not - # the eligibility gate here. total_rcf_income = countable_monthly + ssi_monthly + # Federal SSI parameters used below for the FBR-based disregard. + individual_fbr = parameters(period).gov.ssa.ssi.amount.individual + couple_fbr = parameters(period).gov.ssa.ssi.amount.couple + joint_claim = person("ssi_claim_is_joint", period.this_year) + basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) + # IAC 441—51.3(3) cross-refs 52.1(3)"a": RCF income eligibility + # compares client participation (total monthly income minus the + # personal needs allowance) against 31 × the maximum per diem. The + # 2025 Iowa HHS manual states the rule as: a person meets income + # eligibility when client participation is less than the cost of care + # for a 31-day month. + rcf_client_participation = max_( + 0, total_rcf_income - p.rcf.personal_needs_allowance + ) in_rcf = person("ia_ssa_resides_in_residential_care_facility", period) rcf_income_threshold = p.rcf.days_multiplier * p.rcf.max_per_diem - rcf_income_eligible = total_rcf_income < rcf_income_threshold + rcf_income_eligible = rcf_client_participation < rcf_income_threshold needs_ihhrc = person("ia_ssa_needs_in_home_health_related_care", period) both_need_care = person("ia_ssa_ihhrc_both_need_care", period) - # IAC 441—177.4(1)(f): countable income of the individual and spouse - # living in the home shall be limited to $480.55 per month if one needs - # care or $961.10 (combined) if both need care. - couple_countable = person.marital_unit.sum(countable_monthly) - ihhrc_income_eligible = where( - both_need_care, - couple_countable <= p.ihhrc.max_cost_couple, - countable_monthly <= p.ihhrc.max_cost_single, + # IAC 441—177.4(1)(f) caps combined marital-unit countable income at + # $480.55 (one spouse needs care) or $961.10 (both need care) after + # the basic SSI standard disregard (the applicable FBR for a single + # or joint claim). Compare combined marital-unit income against the + # applicable cap for both configurations so the rule is enforced + # symmetrically. + combined_countable = person.marital_unit.sum(countable_monthly) + ihhrc_countable_after_disregard = max_( + 0, combined_countable - basic_ssi_disregard + ) + ihhrc_cap = where( + both_need_care, p.ihhrc.max_cost_couple, p.ihhrc.max_cost_single ) + ihhrc_income_eligible = ihhrc_countable_after_disregard <= ihhrc_cap in_flh = person("ia_ssa_resides_in_family_life_home", period) # IAC 441—177.4(1)(c): IHHRC recipients must live in their own home, # so exclude those residing in an RCF or family-life home. @@ -57,20 +71,25 @@ def formula(person, period, parameters): has_dependent = person("ia_ssa_dp_has_eligible_dependent", period) dp_configuration = person("ia_ssa_dp_configuration", period) in_dp = dp_configuration != dp_configuration.possible_values.NONE + # IAC 441—52.1(2): DP requires the dependent's countable income to be + # below the dependent income limit. Gate DP at the category level so + # people who qualify for DP but fail the dependent-income test fall + # through to Blind / SMME rather than receiving a zero DP supplement. + dependent_income = person("ia_ssa_dp_dependent_countable_income", period) + dependent_income_eligible = dependent_income < p.dp.dependent_income_limit is_blind = person("is_blind", period.this_year) # IAC 441—52.1(4) blind standard is a federally-administered SSP; # supplement phases to zero when countable income reaches FBR + # state standard. Mirror that ceiling in the category gate so blind # recipients with excess income fall through to the next category. - fbr = parameters(period).gov.ssa.ssi.amount.individual - blind_income_eligible = countable_monthly < fbr + p.blind + blind_income_eligible = countable_monthly < individual_fbr + p.blind smme_eligible = person("ia_ssa_smme_eligible", period) return select( [ eligible & in_rcf & rcf_income_eligible, eligible & needs_ihhrc & in_own_home & ihhrc_income_eligible, eligible & in_flh, - eligible & has_dependent & in_dp, + eligible & has_dependent & in_dp & dependent_income_eligible, eligible & is_blind & blind_income_eligible, eligible & smme_eligible, ], diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py index 0b2270534bf..9dc337a42e4 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py @@ -10,8 +10,15 @@ class ia_ssa_resources_eligible(Variable): reference = "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf" def formula(person, period, parameters): - resources = person("ssi_countable_resources", period.this_year) - p = parameters(period).gov.ssa.ssi.eligibility.resources.limit + individual_resources = person("ssi_countable_resources", period.this_year) joint = person("ssi_claim_is_joint", period.this_year) + # For joint SSI claims, federal SSI counts resources of both spouses + # against the couple limit. Mirror that rule: compare the combined + # marital-unit resources to the couple limit rather than each + # individual amount to the couple limit (which would effectively + # allow $3,000 per spouse). + couple_resources = person.marital_unit.sum(individual_resources) + resources_to_check = where(joint, couple_resources, individual_resources) + p = parameters(period).gov.ssa.ssi.eligibility.resources.limit limit = where(joint, p.couple, p.individual) - return resources <= limit + return resources_to_check <= limit diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py index 37227041e4b..89447da1a09 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py @@ -17,7 +17,26 @@ def formula(person, period, parameters): in_category = category == category.possible_values.IHHRC p = parameters(period).gov.states.ia.hhs.ssa cost = person("ia_ssa_ihhrc_cost_of_care", period) + # IAC 441—177.10(2)(a): payment equals cost of care (capped per person + # at the single cap from 441—177.10(3)) minus client participation, + # where client participation is countable income after the basic SSI + # standard disregard (the applicable FBR for a single or joint claim). + # Compute participation at the marital-unit level and split evenly + # across members so the aggregated SPM-unit total is correct without + # double-counting. + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + individual_fbr = parameters(period).gov.ssa.ssi.amount.individual + couple_fbr = parameters(period).gov.ssa.ssi.amount.couple + joint_claim = person("ssi_claim_is_joint", period.this_year) + disregard = where(joint_claim, couple_fbr, individual_fbr) + combined_countable = person.marital_unit.sum(countable_monthly) + combined_participation = max_(0, combined_countable - disregard) + # Split evenly across marital-unit members (1 person unmarried, 2 if + # married) so the person-level values sum back to the combined total. + client_participation = combined_participation / person.marital_unit.nb_persons() # IAC 441—177.10(3): maximum benefit payable is $480.55 per client, - # inclusive of all services for all providers. The $961.10 is the - # combined couple income cap in IAC 441—177.4(1)(f), not a payment cap. - return in_category * min_(cost, p.ihhrc.max_cost_single) + # inclusive of all services for all providers. + eligible_cost = min_(cost, p.ihhrc.max_cost_single) + return in_category * max_(0, eligible_cost - client_participation) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py index 3832ff3d929..a6c18749075 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_has_full_medicaid.py @@ -7,9 +7,13 @@ class ia_ssa_has_full_medicaid(Variable): definition_period = MONTH label = "Iowa SSA receives full Medicaid" defined_for = StateCode.IA + default_value = False reference = ( "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" ) - - def formula(person, period, parameters): - return person("medicaid_enrolled", period.this_year) + # IAC 441—51.6(1) requires SMME recipients to be enrolled in "full + # Medicaid", which excludes medically-needy/spenddown and MEPD-premium + # pathways. PolicyEngine's generic `medicaid_enrolled` flag includes + # those narrower populations, so Iowa SSA takes an explicit input for + # this flag — users opt in when a household is known to be enrolled in + # full Medicaid. diff --git a/sources/working_references.md b/sources/working_references.md deleted file mode 100644 index 1d81684d431..00000000000 --- a/sources/working_references.md +++ /dev/null @@ -1,366 +0,0 @@ -# Iowa State Supplementary Assistance (SSA) — Working References - -Research compiled 2026-04-16 for PolicyEngine-US implementation. -Every PDF link uses `#page=NN` (file page, not printed page) unless the PDF is single-page. - ---- - -## 0. Program Identification - -- **Official name**: **State Supplementary Assistance (SSA)** — Iowa statutorily and operationally uses "State Supplementary Assistance", *not* "State Supplementary Payment". The program is sometimes shortened to "SSP" in colloquial use but Iowa Code chapter 249 title reads "STATE SUPPLEMENTARY ASSISTANCE". -- **Administering agency**: **Iowa Department of Health and Human Services (HHS)** — reorganized from the Iowa Department of Human Services (DHS) in 2023. The DHS employees' manual is now the "Iowa Department of Health and Human Services Employees' Manual" (Title 6, Chapter B). Many rules and form numbers still reference "DHS". -- **Dual federal/state administration**: - - **SSA-administered** (federal Social Security Administration issues payment on behalf of state): Mandatory State Supplement, Blind Supplement, Dependent Person (DP), Family-Life Home (FLH). - - **State-administered** (Iowa HHS issues payment): Residential Care Facility (RCF), In-Home Health-Related Care (IHHRC), Supplement for Medicare and Medicaid Eligibles (SMME). - - Source: IAC 441—50.2(1) paragraphs a–c; Employees' Manual 6-B p.2. -- **Legal basis**: Iowa Code Chapter 249; IAC 441 Chapters 50, 51, 52, 54, and 177; 20 CFR 416 Subpart T (§§ 416.2001–416.2099). - ---- - -## 1. Iowa Code (Statute) - -### 1.1 Iowa Code § 249.3 — Eligibility -- **Local file**: `/tmp/ia-ssp/code-249-3.pdf` (2 pages; text: `code-249-3.txt`) -- **URL**: https://www.legis.iowa.gov/docs/code/249.3.pdf -- **Key content**: Four subsection groups of eligible persons: - 1. "Essential person" grandfathered from December 1973 categorical assistance (OAA/AB/AD). - 2. Persons receiving care in a licensed adult foster home, boarding home, custodial home, or "another type of protective living arrangement", OR nursing care in the person's own home, who are receiving SSI or would receive SSI but for excess income. - 3. Persons living with a dependent spouse/parent/child/adult child, receiving SSI or would receive SSI but for excess income, with income insufficient to provide for the dependent. - 4. The "Supplement for Medicare and Medicaid Eligibles" (SMME) group — aged 65+ or disabled, living in own home/home of another/group living/medical facility, eligible for SSI but for excess income or SGA, already receiving full Medicaid, eligible for Medicare Part B, income between 120% FPL and Medicaid income limit. - -### 1.2 Iowa Code § 249.9A — Personal Needs Allowance -- **Local file**: `/tmp/ia-ssp/code-249-9A.pdf` (1 page; text: `code-249-9A.txt`) -- **URL**: https://www.legis.iowa.gov/docs/code/2025/249.9A.pdf -- **Key content**: The department shall increase the RCF personal needs allowance by the same percentage and at the same time as federal SSI/Social Security COLA. Added by 2024 Acts, ch 1157, §46. NEW section (2024). - -### 1.3 Iowa Code Chapter 249 (top level) -- The overall "State Supplementary Assistance" chapter title in the Iowa Code. Referred to in manual as "Iowa Code Chapter 249, 'State Supplemental Assistance'" (note: Code title uses "Supplementary"; manual labels with "Supplemental" — both appear). - ---- - -## 2. Iowa Administrative Code (Regulations) - -All chapters below live under **Iowa Administrative Code Title 441 — Human Services Department**, Title V "State Supplementary Assistance". - -### 2.1 IAC 441—Chapter 50 — Application for Assistance -- **Local file**: `/tmp/ia-ssp/iac-441-50.pdf` (4 pages; text: `iac-441-50.txt`) -- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.50.pdf -- **Rule 441—50.1** — Definitions of aged, blind, disabled, applicant, client, "Payment for a dependent relative", "Payment for a protective living arrangement" (family life home), "Payment for residential care". -- **Rule 441—50.2** — Application procedures; paragraphs 50.2(1)(a)–(c) specify federal-vs-state administration of each SSA supplement. -- Recent amendment: ARC 9304C, IAB 5/28/25, effective 7/2/25. - -### 2.2 IAC 441—Chapter 51 — Eligibility -- **Local file**: `/tmp/ia-ssp/iac-441-51.pdf` (~6 pages; text: `iac-441-51.txt`) -- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.51.pdf -- **Rule 441—51.2** — Must apply for all other benefits (SSI, FIP, etc.). -- **Rule 441—51.3** — Supplementation from non-federal sources counts as income, reducing SSA payment. -- **Rule 441—51.4** — Eligibility for residential care (licensed facility, physician's statement, income less than 31 × max per diem). -- **Rule 441—51.5** — Dependent relatives (income/resource rules, financial dependency definition). -- **Rule 441—51.6** — Iowa residency requirement. -- **Rule 441—51.7** — Eligibility for SMME (Medicaid eligibility, SSI-eligibility except SGA/income, not eligible under other SSA group, Medicare Part B, living arrangement, income between 120% FPL and Medicaid limit). -- **Rule 441—51.8** — Income from room and board. -- **Rule 441—51.9** — SSN requirement; overpayment recovery. -- Recent amendment: ARC 9305C, IAB 5/28/25, effective 8/1/25. - -### 2.3 IAC 441—Chapter 52 — Payment -- **Local file**: `/tmp/ia-ssp/iac-441-52.pdf` (~5 pages; text: `iac-441-52.txt`) -- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.52.pdf -- **Rule 441—52.1(249)** — **Assistance standards** (the core rate-setting rule). - - Key text (file page 1): "Assistance standards are the amounts of money allowed on a monthly basis to recipients of state supplementary assistance… **Current assistance standards will be published on the department's website.** Assistance standards will be adjusted annually to reflect cost-of-living adjustments (COLA) adopted by the Social Security Administration, in accordance with 20 CFR §416.2095 and 20 CFR §416.2096 as amended to March 15, 2022. Adjustments to the assistance standards based on COLA are effective January 1 of each year." - - **52.1(1) Protective living arrangement** — family-life home (cross-reference to 441—Chapter 111). - - **52.1(2) Dependent relative** — five household configuration categories (see §5 below for list). - - **52.1(3) Residential care** — Before 7/1/2017: flat per diem OR cost-related per diem. On/after 7/1/2017: cost-related (max per diem). Details six income disregards applied in order, reserve bed days, etc. - - **52.1(4) Blind** — "$22 per month" for blind recipients not receiving another type of SSA (this figure is literally in the rule text). - - **52.1(5) In-home, health-related care** — cross-reference to 441—Chapter 177. - - **52.1(6) Minimum income level cases** — December 1973 MIL preservation. - - **52.1(7) Supplement for Medicare and Medicaid eligibles** — "$1 per month" (literally in the rule text). -- Recent amendment: ARC 9306C, IAB 5/28/25, effective 8/1/25. - -### 2.4 IAC 441—Chapter 54 — Facility Participation -- **Local file**: `/tmp/ia-ssp/iac-441-54.pdf` (~3 pages; text: `iac-441-54.txt`) -- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.54.pdf -- Residential care facility participation rules (not critical to individual eligibility modeling). - -### 2.5 IAC 441—Chapter 177 — In-Home Health-Related Care (IHHRC) -- **Local file**: `/tmp/ia-ssp/iac-441-177.pdf` (~7 pages; text: `iac-441-177.txt`) -- **URL**: https://www.legis.iowa.gov/docs/iac/chapter/04-15-2026.441.177.pdf -- **Rule 441—177.4(1)(f)** — Countable income limits: **$480.55/month** for one person, **$961.10** if both spouses need care, with disregards in order: SSI standard (individual/couple), $65 + ½ earned income, SSI dependent allowance per dependent, unmet medical needs of ineligible spouse, unmet medical needs of applicant/recipient. -- **Rule 441—177.4(1)(g)** — Income deeming rules for children. -- **Rule 441—177.5** — Provider qualifications (age 18+, health assessment, training). -- **Rule 441—177.6** — Physician certification procedure (Form 470-0673). -- **Rule 441—177.7** — Home maintenance allowance and client participation. -- Recent amendment: ARC 6720C, IAB 11/30/22, effective 2/1/23. - -### 2.6 Archive/aggregator links (for verification only) -- Justia: https://regulations.justia.com/states/iowa/agency-441/title-xv/chapter-177/rule-441-177-4/ -- Cornell LII: https://www.law.cornell.edu/regulations/iowa/Iowa-Code-r-441-52.1 — note: Cornell text lags Iowa's IAB amendments. Always cross-check against the legis.iowa.gov PDF. - ---- - -## 3. Iowa HHS Employees' Manual (Policy Manual) - -### 3.1 Title 6, Chapter B — State Supplementary Assistance -- **Local file (two copies with same content)**: - - `/tmp/ia-ssp/6b-manual.pdf` (3,582 lines text, ~78 pages) — smaller file, older PDF build - - `/tmp/ia-ssp/info-2025-03-07.pdf` (3,663 lines text) — identical content -- **URL (small version)**: https://hhs.iowa.gov/media/3987/download -- **URL (March 7, 2025 revision)**: https://hhs.iowa.gov/media/15607/download?inline -- **Revision date**: March 7, 2025. -- **Page references** (use for `#page=NN`): - - **Overview & Legal Basis**: manual p.1 (PDF file page ~5). - - **Policies Applicable to All SSA / Eligibility requirements**: p.2 (PDF ~6). Resource limits $2,000 individual / $3,000 couple. Income must be less than standard for living arrangement. - - **Blind Supplement**: p.15–16. Confirms $22 blind special allowance; maximum income levels $989 individual, $1,472 one-blind-couple, $1,494 both-blind-couple (based on 2025 SSI standards $967/$1,450). - - **Dependent Person**: p.16–26. Dependent income must be <$503/month (2025 value, = SSI dependent allowance). Household income must be less than applicable assistance standard: - - Aged or disabled client and a dependent relative: **$1,470** (2025) - - Aged or disabled client, spouse aged 65+ or disabled, and a dependent relative: **$1,953** (2025) - - Blind client and a dependent relative: **$1,492** (2025) - - Blind client, aged or disabled spouse, and a dependent relative: **$1,975** (2025) - - Blind client, blind spouse, and a dependent relative: **$1,997** (2025) - - **Family-Life Home (FLH)**: p.26–32. Standard allowance **$1,129** (2025). Maximum payment $142 (not $162, to compensate for SSI's $20 disregard). Personal needs **$126** (2025). - - **In-Home Health-Related Care (IHHRC)**: p.32–46. Max cost of care $480.55/month single / $961.10/month couple-both-needing-care. Home maintenance allowance $967 individual / $1,450 couple / $483 per dependent (2025 SSI-linked). - - **Mandatory State Supplement**: p.47–50. December 1973 minimum-income-level preservation cases (legacy). - - **Residential Care Supplement (RCF)**: p.50–70. Flat per diem $17.86, max cost-related per diem **$37.60** (2025). Personal needs **$126** (2025). Client participation rules detailed on p.57–67. - - **Supplement for Medicare and Medicaid Eligibles (SMME)**: p.70–74. Fixed $1/month paid quarterly. Requires dual Medicare Part B + full Medicaid, income between 120% FPL and Medicaid limit, not eligible under another SSA group. - -### 3.2 Additional manual: April 11, 2025 revision -- **Local file**: `/tmp/ia-ssp/info-2025-04-11.pdf` -- **URL**: https://hhs.iowa.gov/media/15819/download?inline -- 4,377 lines — this is Title 8 Chapter E (Medicaid Income), which includes tangential SSA references; **not the SSA-specific chapter**. - ---- - -## 4. Informational Letters / Rate-setting Announcements - -### 4.1 Informational Letter No. 2651-MC-FFS (December 30, 2024) -- **Local file**: `/tmp/ia-ssp/il-2024-12-30.pdf` (2 pages; text: `il-2024-12-30.txt`) -- **URL**: https://secureapp.dhs.state.ia.us/IMPA/Information/ViewDocument.aspx?viewdocument=634b265a-2fa6-4fdb-a4ed-0ce94e32b993 -- **Content**: Effective January 1, 2025: - - RCF **maximum per diem rate**: $36.82 → **$37.60** - - **Flat per diem rate**: remains at **$17.86** (unchanged since 2/1/2004) - - **Personal needs allowance**: $123.00 → **$126.00** - - Based on "average Medicaid copays paid by RCF Medicaid members in SFY 2024 in conjunction with the COLA increase announced by SSA". - ---- - -## 5. Current 2026 Rates — Iowa HHS SSA Standards Page - -### 5.1 State Supplementary Assistance | Health & Human Services -- **URL**: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance -- **Effective**: January 1, 2026 -- **Single-page HTML** (no PDF anchor needed) - -**Family Home Life (FLH)** — Effective January 1, 2026 -| Component | Amount | -|---|---| -| Payment to Family | $1,026.00 | -| Personal Needs Allowance | $130.00 | -| Payment Standard (total) | $1,156.00 | - -**Dependent Person (DP)** — Effective January 1, 2026 -| Category | Income Standard | -|---|---| -| Maximum Payment (per person) | $518.00 | -| Aged or Disabled Client and Dependent Relative | $1,512.00 | -| Aged or Disabled Client, Eligible Spouse, and Dependent Relative | $2,009.00 | -| Blind Client and Dependent Relative | $1,534.00 | -| Blind Client, Aged or Disabled Spouse, and Dependent Relative | **$3,031.00** ⚠️ SUSPECTED TYPO — see §9 | -| Blind Client, Blind Spouse, and Dependent Relative | $2,053.00 | - -**Residential Care Facility (RCF)** — Effective January 1, 2026 -| Component | Amount | -|---|---| -| Personal Needs Allowance | $130.00 | -| Flat per Diem Rate | $17.86 | -| Maximum Cost-Related per Diem Rate | $38.47 | - -### 5.2 Current rates NOT published on the HHS SSA page -The HHS SSA page does not publish current-year values for: -- Blind supplement ($22/month — hardcoded in IAC 441—52.1(4)) -- In-Home Health-Related Care max cost-of-care ($480.55 / $961.10 — hardcoded in IAC 441—177.4(1)(f)) -- SMME payment ($1/month — hardcoded in IAC 441—52.1(7)) -- Home maintenance allowances ($967 / $1,450 / $483 — derived from federal SSI FBR) -- 2026 manual update with revised FLH/DP/IHHRC amounts (not yet published; March 7, 2025 is the latest) - ---- - -## 6. Historical Pamphlet: Comm. 18 (State Supplementary Assistance) - -- **Local file**: `/tmp/ia-ssp/comm18.pdf` (3 pages; text: `comm18.txt`) -- **URL**: https://hhs.iowa.gov/media/6413/download -- **Revision date**: Comm. 18 (Rev. 3/10) — March 2010 -- **Content**: Consumer-facing explanation of SSA. Lists 5 special-needs categories: - - Special Blind Allowance - - Residential Care - - Family-Life Home - - Dependent Relative - - In-Home Health-Related Care -- Note: Comm. 18 does NOT list the SMME ($1/month) supplement (which was added by 2003 Iowa legislation for the "pass-through" requirement) or the Mandatory State Supplement (1973 MIL grandfathered cases) — likely because this consumer pamphlet predates some additions. Authoritative list of SSA types is in the 6-B manual and IAC 441—52.1. - ---- - -## 7. SSA 2011 State Assistance Programs Report (Iowa) - -### 7.1 Availability -- **Primary URL (SSA)**: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.html — **403 blocked** to automated tools (including curl with browser UA) -- **Wayback Machine (working)**: https://web.archive.org/web/2024/https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.html -- **Extracted text**: `/tmp/ia-ssp/ssa-2011-ia.txt` (209 lines, complete) - -### 7.2 2011 Payment Levels (from Table 1 — verbatim) -Optional state supplementation payment levels, January 2011 (in dollars): - -| Living arrangement | State code | Combined federal+state (Individual) | Combined federal+state (Couple) | State supplementation (Individual) | -|---|---|---|---|---| -| Living independently (blind) | A | 696.00 | 1,055.00 (a) | 22.00 | -| Living in the household of another (blind) | B | 471.34 | 718.00 (a) | 22.00 | -| Living with a dependent person (Aged and disabled) | C | 1,018.00 | 1,355.00 | 344.00 | -| Living with a dependent person (Blind) | C | 1,040.00 | 1,399.00 | 366.00 | -| Family life or boarding home (Aged and disabled) | D | 816.00 | 1,652.00 | 142.00 | -| Family life or boarding home (Blind) | D | 838.00 | 1,696.00 | 164.00 | -| Living with a dependent person in the household of another (Aged and disabled) | H | 793.34 | 1,018.00 | 344.00 | -| Living with a dependent person in the household of another (Blind) | H | 815.34 | 1,062.00 | 366.00 | -| Family life or boarding home with 1/3 reduction (Aged and disabled) | I | 591.34 | 1,315.00 | 142.00 | -| Family life or boarding home with 1/3 reduction (Blind) | I | 613.34 | 1,359.00 | 164.00 | -| Residential care | . . . | 965.34 | . . . | 291.34 (b) | -| In-home health care | . . . | 1,154.55 | 1,972.10 (c) | 480.55 (d) | - -**Footnotes**: -- (a) "Payment level when both members of a couple are blind; when only one member is blind, payment is reduced by $22." -- (b) "Amount based on allowable costs of residential care (up to $28.14 per day), plus a personal needs allowance of $93 per month, minus the federal SSI payment. State administers payments." -- (c) "Payment is based on both members of a couple needing in-home health-related care. When one member needs care, payment is reduced by $480.55. State administers payments." -- (d) "Payment is based on actual cost of in-home health-related care up to a maximum of $480.55, plus basic federal benefit. State administers payments." - -### 7.3 2011 Recipient Counts (from Table 2) -| Living arrangement | State code | Total | Aged | Blind | Disabled Adults | Disabled Children | -|---|---|---|---|---|---|---| -| **All recipients** | — | **5,281** | 594 | 453 | 3,927 | 307 | -| Living independently (blind) | A | 535 | 0 | 424 | 0 | 111 | -| Living in the household of another (blind) | B | 10 | 0 | 9 | 0 | 1 | -| Living with a dependent person | C | 1,473 | 109 | 18 | 1,176 | 170 | -| Family life or boarding home | D and I | 4 | 0 | 0 | 4 | 0 | -| Living with a dependent person in the household of another | H | 1 | 1 | 0 | 0 | 0 | -| Residential care | — | 1,703 | 299 | — | 1,404 | 0 | -| In-home health care | — | 1,531 | 182 | — | 1,324 | 25 | -| Medicaid facility | — | 24 | 3 | 2 | 19 | 0 | - -### 7.4 Program administration notes (from SSA 2011 Iowa page, verbatim) -- Mandatory Minimum Supplementation: Social Security Administration. -- Optional State Supplementation: "State Department of Human Services administers supplemental payments for persons receiving residential or in-home health-related care, and persons who are eligible for the supplement for Medicare and Medicaid eligible. Social Security Administration administers all other supplemental payments." -- Effective dates: January 1, 1974 (blind); May 1, 1974 (aged and disabled); **October 1, 2003** (SMME — supplement for Medicare and Medicaid eligible). -- Statutory basis: Code of Iowa, chapter 249. -- Total expenditures: "State-administered payments for calendar year 2010 are not available, but $5,362,000 in federally administered payments were made to SSI recipients." - -**Note**: The SSA 2011 report is the **last state-by-state SSP report SSA published**; it was discontinued thereafter. Use this as the authoritative historical snapshot for rates/eligibility as of January 2011. - -### 7.5 Derivation of 2011 state-only portions from combined totals -Working from 2011 SSI FBR ($674 individual / $1,011 couple): -- Blind (Individual) state-only = $22 (directly stated) -- Living with dependent (Aged/Disabled), Individual: combined $1,018 − federal $674 = **$344 state portion** ✓ matches -- Family-life home (Aged/Disabled), Individual: combined $816 − federal $674 = **$142** ✓ matches -- Residential care, Individual: per footnote (b), cost-based formula; $28.14/day × 31 = $872.34 + $93 PNA = $965.34 total = $291.34 state portion (after federal SSI). - ---- - -## 8. Historical rates from Wayback Machine (IA HHS SSA page) - -The Iowa HHS SSA rates page has archived snapshots available at: -- 2024 snapshot: https://web.archive.org/web/2024/https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance (shows Jan 1, 2025 rates) -- 2025 snapshot: https://web.archive.org/web/2025/https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance (shows Jan 1, 2025 rates) - -**Note**: Pre-2024 snapshots of the current URL and of the older `dhs.iowa.gov/state-supplementary-assistance-program` URL were not available in Wayback (404). This limits ability to verify historical year-by-year amounts beyond the 6-B manual's current rates and the SSA 2011 report. - -**Iowa HHS rates comparison (2025 → 2026)**: -| Item | 2025 | 2026 | COLA-implied? | -|---|---|---|---| -| FLH Payment to Family | $1,003 | $1,026 | 2.29% (≈ 2.5% COLA) ✓ | -| FLH Personal Needs Allowance | $126 | $130 | 3.17% — higher than COLA | -| FLH Payment Standard | $1,129 | $1,156 | 2.39% ✓ | -| DP Maximum Payment | $503 | $518 | 2.98% ≈ 2.5% COLA ✓ | -| DP Aged/Disabled + dep | $1,470 | $1,512 | 2.86% ✓ | -| DP Aged/Disabled + spouse + dep | $1,953 | $2,009 | 2.87% ✓ | -| DP Blind + dep | $1,492 | $1,534 | 2.82% ✓ | -| DP Blind + A/D spouse + dep | $1,975 | **$3,031** | **53.5% ⚠️ TYPO SUSPECTED** | -| DP Blind + blind spouse + dep | $1,997 | $2,053 | 2.80% ✓ | -| RCF Personal Needs | $126 | $130 | 3.17% | -| RCF Flat per Diem | $17.86 | $17.86 | frozen since 2/1/2004 | -| RCF Max Cost-Related per Diem | $37.60 | $38.47 | 2.31% ✓ | - ---- - -## 9. Known Issues / Verification Flags - -### 9.1 Suspected typo on Iowa HHS SSA page (DP Blind + Aged/Disabled spouse + dep) -- 2025 value: $1,975 (from 6-B manual and 2024/2025 Wayback) -- 2026 value as published: **$3,031** -- Expected 2026 value from COLA: ~$2,031 (consistent with the 2.8% applied to other 2026 DP rows) -- **Likely explanation**: Transposition/typo where "$2,031" became "$3,031". -- **Recommended action**: Flag this in the PR description as a verification TODO. Before committing parameter values for 2026, email Iowa HHS or wait for the next 6-B manual revision to confirm. - -### 9.2 2026 manual not yet published -- Latest 6-B manual is **March 7, 2025**. For 2026 implementation, the current (Effective January 1, 2026) rates on the HHS SSA page are the only source for FLH/DP/RCF. -- Blind, IHHRC, and SMME rates are controlled by IAC (and frozen or COLA-indexed from federal SSI standards), so the 2025 manual is still authoritative for those. - -### 9.3 Historical rates before 2011 and between 2011–2024 -- SSA stopped publishing state-by-state SSP reports after January 2011. -- Iowa's 2015–2023 rate snapshots were not archived on Wayback Machine. -- Reconstruction would require either: - - Manual request to Iowa HHS for historical assistance standards schedule; OR - - Calculation by applying federal SSI COLA sequence to the 2011 figures forward (approximate, because some rates are not pure COLA — e.g., the $17.86 flat per diem has been frozen since 2/1/2004). - ---- - -## 10. Closed PR #7734 (mattunrath/ia-ssp) - -- **Branch**: `mattunrath/ia-ssp` on GitHub remote -- **Single commit**: `02a0314df9` "Initial commit for Iowa SSP implementation" dated 2026-03-07 -- **Content**: Branch was initialized but **never committed source or variable files**. Only commit message; no actual implementation, no `sources/` directory, no parameters. -- **Use**: **Do not copy** — branch has no content to copy. Sources were independently collected here. - ---- - -## 11. Other supporting material - -### 11.1 Iowa Legislature Budget Unit: State Supplementary Assistance (FT doc 16896) -- **Local file**: `/tmp/ia-ssp/budget-unit.pdf` (text: `budget-unit.txt`, 53 lines) -- **URL**: https://www.legis.iowa.gov/docs/publications/FT/16896.pdf -- Contains legislative budget overview of SSA appropriations. - -### 11.2 ARC 3715C — Iowa Administrative Rules Notice -- **URL**: https://rules.iowa.gov/Notice/Details/3715C -- Amendment notice referenced in IAC Chapter 52's revision history. Confirms the "periods of eligibility beginning July 1, 2017" transition to cost-related-only RCF reimbursement. - -### 11.3 WorkWorld Iowa SSA reference (secondary / for cross-verification only) -- **URL**: https://help.workworldapp.com/wwwebhelp/state_supplementary_assistance_eligibility_requirements_iowa.htm -- References: Iowa DHS Employees' Policy Manual Title 6 Chapter B; 20 CFR 416.2001; Iowa Code § 249.3. - -### 11.4 Iowa Admin. Code Justia portal (secondary / for cross-verification only) -- **URL**: https://regulations.justia.com/states/iowa/441/title-v/chapter-51/441-51-3/ - -### 11.5 Iowa HHS application forms (SSA application, not source for rates) -- English: https://hhs.iowa.gov/media/5825/download?inline -- Spanish: https://hhs.iowa.gov/media/5828/download?inline -- Medicaid brochure: https://hhs.iowa.gov/media/6420/download?inline -- Application portal: https://hhsservices.iowa.gov/apspssp/ssp.portal - ---- - -## 12. Fetch status summary - -### Successful fetches -- Iowa HHS SSA current rates page ✓ -- Iowa Code § 249.3 (PDF) ✓ -- Iowa Code § 249.9A (PDF) ✓ -- IAC Chapters 50, 51, 52, 54, 177 (PDFs) ✓ -- 6-B Employees' Manual (PDF) — full 78-page text extracted ✓ -- Comm. 18 pamphlet ✓ -- Informational Letter 2651-MC-FFS (Dec 30, 2024 — RCF rate update) ✓ -- Iowa Legislature budget FT document ✓ -- **SSA 2011 Iowa report via Wayback Machine** ✓ (after direct SSA 403) - -### Failed fetches (403/404) — CRITICAL for unreachable-reference checkpoint -- **`https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.html`** — SSA blocks automated tools with HTTP 403. **Resolution**: content was successfully retrieved via Wayback Machine at `https://web.archive.org/web/2024/https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.html`. If primary citation is needed, user may need to download the SSA URL manually in a browser. The Wayback version is byte-for-byte the same HTML. -- **Historical snapshots of `dhs.iowa.gov/state-supplementary-assistance-program`** — 404 on all Wayback years tried (2015, 2018, 2019, 2020, 2022). DHS→HHS reorganization likely destroyed older archives. **Impact**: cannot directly verify year-by-year FLH/DP/RCF rates from 2011 to 2024. Mitigation: use the 2011 SSA report for the 2011 baseline; the 2025 HHS page/Wayback snapshot for the 2024/2025 rates; and accept that 2012–2023 rates will need to be either reconstructed via COLA application to 2011 figures, or obtained via direct request to Iowa HHS. - -### No attempt made (not needed for this scope) -- Individual annual IAB notices filing COLA adjustments (dozens of ARC numbers listed in IAC Ch 52's amendment history — each year has one, and for current modeling the published HHS standards are sufficient). - ---- From b27236d4f989a95d99690b30b8fc2e89bd2bd264 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 23 Apr 2026 00:17:18 -0400 Subject: [PATCH 12/23] Collapse Iowa SSA per-category supplement variables Replace the six supplement variables (ia_ssa_blind_supplement, ia_ssa_dp_supplement, ia_ssa_flh_supplement, ia_ssa_ihhrc_supplement, ia_ssa_rcf_supplement, ia_ssa_smme_supplement) with a single payment formula in ia_ssa that selects over ia_ssa_living_arrangement. Rename ia_ssa_category -> ia_ssa_living_arrangement (enum and variable) to match the reality of what the enum represents. Helper variables that represent genuine inputs (residency flags, cost-of-care, DP configuration, Medicaid/Part B flags, SMME eligibility, both-need-care) remain unchanged. Tests reorganized: - ia_ssa_living_arrangement.yaml holds routing/priority tests - ia_ssa.yaml consolidates the six per-category payment tests with outputs renamed to ia_ssa; one BLIND-in-RCF case updated to assert the routed RCF payment rather than the zero blind value. All 77 Iowa SSA YAML tests pass; microsim unaffected. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 1486 +++++++++++++++++ .../ia/hhs/ssa/ia_ssa_blind_supplement.yaml | 227 --- .../ia/hhs/ssa/ia_ssa_dp_supplement.yaml | 244 --- .../ia/hhs/ssa/ia_ssa_flh_supplement.yaml | 167 -- .../ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml | 348 ---- ...ry.yaml => ia_ssa_living_arrangement.yaml} | 30 +- .../ia/hhs/ssa/ia_ssa_rcf_supplement.yaml | 262 --- .../ia/hhs/ssa/ia_ssa_smme_supplement.yaml | 211 --- .../ia/hhs/ssa/dp/ia_ssa_dp_supplement.py | 33 - .../ia/hhs/ssa/flh/ia_ssa_flh_supplement.py | 30 - .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 75 +- .../ia/hhs/ssa/ia_ssa_blind_supplement.py | 29 - ...tegory.py => ia_ssa_living_arrangement.py} | 31 +- .../hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py | 42 - .../ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py | 33 - .../ia/hhs/ssa/smme/ia_ssa_smme_supplement.py | 19 - 16 files changed, 1584 insertions(+), 1683 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml rename policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/{ia_ssa_category.yaml => ia_ssa_living_arrangement.yaml} (93%) delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py rename policyengine_us/variables/gov/states/ia/hhs/ssa/{ia_ssa_category.py => ia_ssa_living_arrangement.py} (85%) delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml new file mode 100644 index 00000000000..fec588ec726 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml @@ -0,0 +1,1486 @@ +# Iowa SSA consolidated payment tests. +# +# ia_ssa is computed by selecting over ia_ssa_living_arrangement and applying +# the category-specific payment formula. Tests here exercise each arrangement's +# math (Blind, DP, FLH, RCF, IHHRC, SMME) plus multi-category integrations. +# Routing priority (RCF > IHHRC > FLH > DP > BLIND > SMME > NONE) is verified +# separately in ia_ssa_living_arrangement.yaml. + +# ============================================================================ +# BLIND supplement tests (IAC 441—52.1(4): flat $22, frozen since 2011). +# ============================================================================ +- name: Case 1, blind aged Iowan receives flat 22 dollar supplement plus federal SSI. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + is_blind: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + is_ssi_eligible: [true] + ssi: [967] + ia_ssa_eligible: [true] + ia_ssa_living_arrangement: [BLIND] + ia_ssa: [22] + +- name: Case 2, non-blind aged Iowan receives no blind supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + is_blind: false + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa: [0] + +- name: Case 3, blind person with excess resources receives no supplement. + period: 2025-01 + input: + people: + person1: + age: 40 + is_blind: true + employment_income: 0 + ssi_countable_resources: 5_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_resources_eligible: [false] + ia_ssa_eligible: [false] + ia_ssa: [0] + +- name: Case 4, blind RCF resident routed to RCF (IAC 441-52.1(4) exclusivity). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Per IAC 441-52.1(4) blind is not paid concurrently with another SSA + # arrangement. RCF outranks BLIND in the priority cascade, so the person + # is paid as RCF: 31 * $37.60 - ($967 SSI - $126 PNA) = $324.60. + ia_ssa_living_arrangement: [RCF] + ia_ssa: [324.60] + +- name: Case 5, blind Iowan with earnings still gets blind supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + is_blind: true + # Earned income: $500/mo; after blind/disabled working student? + # The blind supplement has no income test at the category level + # beyond SSI categorical eligibility (which ignores income). + employment_income: 6_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Still ssi_eligible (passes ABD + resources + immigration). + is_ssi_eligible: [true] + ia_ssa_eligible: [true] + ia_ssa_living_arrangement: [BLIND] + ia_ssa: [22] + +- name: Case 6, blind person at 2026 still receives frozen 22 dollar supplement. + period: 2026-01 + input: + people: + person1: + age: 40 + is_blind: true + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Blind supplement frozen at $22 since 2017. + ia_ssa: [22] + +- name: Case 7, blind person with income above FBR plus state standard gets zero supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + social_security_retirement: 14_400 # $1,200/mo gross + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,200/mo SS gross -> $1,180/mo countable (after $20 disregard). + # FBR $967, blind state standard $22, total $989. Countable $1,180 + # exceeds $989 -> blind income gate in ia_ssa_living_arrangement excludes, + # so category drops to NONE and supplement is $0. + ia_ssa_living_arrangement: [NONE] + ia_ssa: [0] + +- name: Case 8, blind person with income just above FBR gets partial supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + social_security_retirement: 12_000 # $1,000/mo gross + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,000/mo SS gross -> $980/mo countable (after $20 disregard). + # FBR $967, blind state standard $22, total $989. + # Federally-administered formula: max(0, 989 - max(980, 967)) = 9. + ia_ssa_living_arrangement: [BLIND] + ia_ssa: [9] + +# ============================================================================ +# DP (Dependent Person) supplement tests (IAC 441—52.1(2): 5 configurations). +# ============================================================================ +# IAC 441—52.1(2): DP is federally-administered per POMS SI 01415.050.F. +# Federally-administered SSP formula: +# supplement = max(0, payment_standard - max(countable, FBR)) +# capped at max_per_person_cap ($503 in 2025, $518 in 2026). +# Also requires dependent's countable income < dependent_income_limit. + +- name: Case 1, person with no DP configuration gets zero supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: NONE + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa: [0] + +- name: Case 2, person with excess resources gets zero DP supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ssi_countable_resources: 5_000 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_eligible: [false] + ia_ssa: [0] + +- name: Case 3, DP supplement capped at per-person maximum 503 dollars. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Standard $1,997 minus federal SSI and income; well above $503 cap + ia_ssa: [503] + +- name: Case 4, DP supplement cap rises to 518 dollars in 2026. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa: [518] + +- name: Case 5, aged client with aged spouse and dependent child integration. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person2: + age: 68 + employment_income: 0 + ia_ssa_dp_configuration: NONE + person3: + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1, person2] + second_marital_unit: + members: [person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: IA + output: + # person1: DP capped at $503. + # person2: income above 120% FPL for household of 3 would be required + # for SMME ($26,650 × 1.2 / 12 = $2,665/mo); but income is $0, so not + # SMME-eligible -> NONE. + # person3: child -> NONE. + ia_ssa_living_arrangement: [DP, NONE, NONE] + ia_ssa: [503, 0, 0] + +- name: Case 6, dependent income above limit disqualifies DP supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 600 # > $503 limit + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Dependent income exceeds the limit -> DP category gate fails. Person + # is 70 with no other qualifying category -> NONE -> supplement 0. + ia_ssa_living_arrangement: [NONE] + ia_ssa: [0] + +- name: Case 7, 2017 DP aged-or-disabled-with-dependent uses 1114 dollar standard and 379 dollar cap. + period: 2017-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # 2017 AGED_OR_DISABLED_WITH_DEPENDENT payment standard $1,114; FBR $735; + # max_per_person_cap $379. Federally-administered formula: + # max(0, 1114 - max(0, 735)) = $379 -> capped at $379. + ia_ssa_living_arrangement: [DP] + ia_ssa: [379] + +- name: Case 8, DP supplement phases down when countable income exceeds FBR. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 20_640 # $1,720/mo + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,720/mo SS gross -> $1,700/mo countable. Payment standard $1,997, + # FBR $967. Federally-administered formula: + # max(0, 1997 - max(1700, 967)) = $297 (under the $503 cap). + ia_ssa: [297] + +# ============================================================================ +# FLH (Family-Life Home) supplement tests (IAC 441—52.1(1)). +# ============================================================================ +# IAC 441—52.1(1): FLH is federally-administered per POMS SI 01415.050.F. +# Federally-administered SSP formula: +# supplement = max(0, assistance_standard - max(countable, FBR)) +# capped at max_supplement ($142). + +- name: Case 1, aged FLH resident with zero income (federal SSI plus capped state supplement). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills to FBR $967; assistance standard $1,129; + # raw supplement = 1,129 - max(0, 967) = 162; capped at $142. + is_ssi_eligible: [true] + ssi: [967] + ia_ssa_eligible: [true] + ia_ssa_living_arrangement: [FLH] + ia_ssa: [142] + +- name: Case 2, person not in FLH receives zero FLH supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_family_life_home: false + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa: [0] + +- name: Case 3, FLH resident with excess resources receives zero. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ssi_countable_resources: 5_000 + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_eligible: [false] + ia_ssa: [0] + +- name: Case 4, FLH resident 2026 still capped at 142 dollars. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Cap is frozen at $142 even though standard and PNA rise in 2026 + ia_ssa: [142] + +- name: Case 5, FLH supplement phases down when countable income exceeds FBR. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 12_840 # $1,070/mo gross + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,070/mo SS gross -> $1,050/mo countable (after $20 disregard). + # Assistance standard $1,129; FBR $967. + # max(0, 1129 - max(1050, 967)) = $79 (under the $142 cap). + ia_ssa: [79] + +- name: Case 6, FLH supplement is zero when countable income equals or exceeds standard. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 14_400 # $1,200/mo gross + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Countable $1,180/mo; standard $1,129; raw = max(0, 1129 - 1180) = 0. + ia_ssa: [0] + +# ============================================================================ +# IHHRC (In-Home Health-Related Care) supplement tests (IAC 441—177). +# ============================================================================ +# IAC 441—177.10(2)(a): payment = max(0, min(cost, per-person cap) - +# client participation), where client participation is marital-unit +# countable income minus the basic SSI standard disregard (the applicable +# FBR for a single or joint claim), split evenly across the marital unit. +# IAC 441—177.10(3): IHHRC max benefit payable is $480.55 per person, inclusive +# of all services for all providers. The $961.10 in 441—177.4(1)(f) is the +# combined couple income cap, NOT a per-person payment cap. +# IAC 441—177.4(1)(c): recipient must live in own home (not in RCF or FLH). +# IAC 441—177.4(1)(f): income cap on countable income after the basic SSI +# standard disregard — individual <= $480.55, or combined couple <= $961.10 +# when both spouses need care. + +- name: Case 1, individual IHHRC cost below max pays actual cost. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 450 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Cost $450 below max $480.55 -> pays actual $450 + ia_ssa: [450] + +- name: Case 2, individual IHHRC cost above max is capped at 480.55 dollars. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 600 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Cost $600 > max $480.55 -> capped + ia_ssa: [480.55] + +- name: Case 3, person not needing IHHRC receives zero supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: false + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa: [0] + +- name: Case 4, person needing IHHRC with excess resources receives zero. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ssi_countable_resources: 5_000 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_eligible: [false] + ia_ssa: [0] + +- name: Case 5, couple both needing IHHRC use couple cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 900 + person2: + age: 68 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 900 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Both need care -> combined income cap $961.10 (combined countable = 0). + # Payment max is $480.55 per person (441—177.10(3)). + # Each cost $900 > per-person max $480.55 -> capped at $480.55 each. + ia_ssa_ihhrc_both_need_care: [true, true] + ia_ssa: [480.55, 480.55] + +- name: Case 6, couple both needing IHHRC with high cost capped at 480.55 dollars per person. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 1_500 + person2: + age: 68 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 1_500 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Both need care -> combined income cap $961.10 (combined countable = 0). + # Payment max is $480.55 per person (441—177.10(3)). + # Each cost $1,500 > per-person max $480.55 -> capped at $480.55 each. + ia_ssa: [480.55, 480.55] + +- name: Case 7, couple with only one spouse needing IHHRC uses single cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 800 + person2: + age: 68 + employment_income: 0 + ia_ssa_needs_in_home_health_related_care: false + ia_ssa_ihhrc_cost_of_care: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Only person1 needs care -> both_need_care false -> single cap $480.55 + ia_ssa_ihhrc_both_need_care: [false, false] + ia_ssa: [480.55, 0] + +- name: Case 8, person with countable income above single cap is ineligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 20_000 # $1,667/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Countable $1,647/mo minus individual FBR disregard $967 = $680, which + # exceeds the single cap $480.55 -> not in IHHRC category -> no supplement. + ia_ssa: [0] + +- name: Case 9, single person with countable income below FBR gets full supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 9_600 # $800/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $800/mo SS gross, countable $780/mo. Individual FBR disregard $967 makes + # income after disregard 0 -> passes single cap. Client participation is + # 0 -> supplement equals cost $400. + ia_ssa: [400] + +- name: Case 10, couple both needing IHHRC with combined countable below couple FBR. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 7_200 # $600/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + person2: + age: 68 + social_security_retirement: 7_200 # $600/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Each spouse's countable unearned is about $580/mo after the $20 general + # disregard, combined ~$1,160. Couple FBR disregard $1,450 leaves 0 after + # disregard -> passes couple cap $961.10. Client participation is 0 -> + # each person's supplement equals cost $400. + ia_ssa_ihhrc_both_need_care: [true, true] + ia_ssa: [400, 400] + +- name: Case 11, couple both needing IHHRC with combined countable above couple cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 15_840 # $1,320/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + person2: + age: 68 + social_security_retirement: 15_840 # $1,320/mo gross + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Each spouse's countable ~$1,300/mo; combined ~$2,600. After couple FBR + # disregard $1,450 -> $1,150 countable, which exceeds the couple cap + # $961.10 -> both ineligible. + ia_ssa_ihhrc_both_need_care: [true, true] + ia_ssa: [0, 0] + +# ============================================================================ +# RCF (Residential Care Facility) supplement tests (IAC 441—52.1(3)). +# ============================================================================ +# IAC 441—52.1(3): payment in RCF = (31 * max_per_diem) - client_participation +# where client_participation = total_monthly_income - personal_needs_allowance. +# Total income = SSI-countable income + federal SSI payment. +# RCF income eligibility: client_participation < 31 * max_per_diem. + +- name: Case 1, aged RCF resident with no income (SSI fills to FBR). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills to 2025 FBR $967; RCF supplement = + # 31 * $37.60 - ($967 - $126) = $1,165.60 - $841 = $324.60 + is_ssi_eligible: [true] + ssi: [967] + ia_ssa_eligible: [true] + ia_ssa_living_arrangement: [RCF] + ia_ssa: [324.60] + +- name: Case 2, RCF per diem above max is capped at 37.60 dollars per day. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 50 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Capped cost = 31 * $37.60 = $1,165.60; CP $841; supplement $324.60 + ia_ssa: [324.60] + +- name: Case 3, person not in RCF receives zero supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: false + ia_ssa_rcf_cost_per_diem: 30 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa: [0] + +- name: Case 4, aged RCF resident in 2026 uses higher 38.47 dollar per diem. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 38.47 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills to 2026 FBR $994; RCF supplement = + # 31 * $38.47 - ($994 - $130) = $1,192.57 - $864 = $328.57 + is_ssi_eligible: [true] + ssi: [994] + ia_ssa_living_arrangement: [RCF] + ia_ssa: [328.57] + +- name: Case 5, RCF resident with zero reported per diem receives zero. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # cost_of_care = 0; max(0, 0 - client_participation) = 0 + ia_ssa: [0] + +- name: Case 6, RCF resident with 12000 dollar Social Security has higher client participation. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 12_000 # $1,000/mo + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $1,000/mo SS, countable $980; no SSI (countable > FBR minus $0 state + # standard); total monthly income $980; client participation + # $980 - $126 = $854; supplement = $1,165.60 - $854 = $311.60. + ia_ssa: [311.60] + +- name: Case 7, RCF resident with income above 31 times max per diem is ineligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 30_000 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # SS $2,500/mo exceeds SSI FBR; client participation > + # 31 * $37.60 income limit -> not in RCF category -> no supplement + ia_ssa: [0] + +- name: Case 8, 2018 RCF resident uses the 99 dollar PNA effective March 2018. + period: 2018-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 30.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Federal SSI fills to 2018 FBR $750. 2018 RCF: max_per_diem $30.60, + # PNA $99 (per March 28, 2018 IAC rule update). CP $750 - $99 = $651. + # Cost of care 31 * $30.60 = $948.60. Supplement $948.60 - $651 = $297.60. + ssi: [750] + ia_ssa_living_arrangement: [RCF] + ia_ssa: [297.60] + +- name: Case 9, RCF resident with excess resources receives zero supplement. + period: 2025-01 + input: + people: + person1: + age: 70 + employment_income: 0 + ssi_countable_resources: 5_000 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Resources $5,000 > $2,000 limit -> ia_ssa_eligible false + ia_ssa_eligible: [false] + ia_ssa: [0] + +# ============================================================================ +# SMME (Supplement for Medicare and Medicaid Eligibles) tests (IAC 441—52.1(7)). +# ============================================================================ +# SMME is a $1/month technical SSP pathway for people who meet all SSI +# categorical eligibility (aged/blind/disabled, resources, immigration) but +# whose income exceeds the federal SSI benefit rate. Per IAC 441—51.7(6), +# income must exceed 120% of the federal poverty level. 2025 FPL (1 person, +# contiguous US) = $15,650; 120% = $18,780/year or $1,565/month. + +- name: Case 1, aged Iowan with income above 120% FPL, full Medicaid and Part B. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 24_000 # $2,000/month + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Income $2,000/mo; countable $1,980 after $20 exclusion; + # 120% FPL for 1 person (2025, contiguous) = $1,565/mo; exceeds threshold. + # No SSI (countable > FBR $967). SMME pays $1. + is_ssi_eligible: [true] + ssi: [0] + ia_ssa_eligible: [true] + ia_ssa_living_arrangement: [SMME] + ia_ssa: [1] + +- name: Case 2, aged Iowan with low income (below 120% FPL) is not SMME-eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 12_000 # $1,000/month + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Income $1,000/mo; countable $980 after $20 exclusion; below 120% FPL + # $1,565/mo. SMME-ineligible; person gets regular SSI instead + # (FBR $967 - countable $980 < 0, so no federal SSI either). + ia_ssa_living_arrangement: [NONE] + ia_ssa: [0] + +- name: Case 3, aged Iowan without full Medicaid gets no SMME. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 24_000 + ia_ssa_has_full_medicaid: false + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_living_arrangement: [NONE] + ia_ssa: [0] + +- name: Case 4, aged Iowan without Medicare Part B gets no SMME. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 24_000 + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: false + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_living_arrangement: [NONE] + ia_ssa: [0] + +- name: Case 5, person with excess resources receives zero SMME. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 24_000 + ssi_countable_resources: 5_000 + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false + ia_ssa_eligible: [false] + ia_ssa: [0] + +- name: Case 6, income exactly at 120% FPL boundary is not SMME-eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # $18,780/year gross = $1,565/month; countable = $1,545 after $20 + # exclusion, which is below the $1,565 threshold. Boundary check. + social_security_retirement: 18_780 + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # Statute requires income to EXCEED 120% FPL (>, not >=). + ia_ssa_living_arrangement: [NONE] + ia_ssa: [0] + +- name: Case 7, aged Iowan at 2026 rates with income above 120% FPL. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # 2026 FPL (1 person, contiguous) = $15,960; 120% = $19,152/year. + social_security_retirement: 30_000 # $2,500/month, well above threshold + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + ia_ssa_living_arrangement: [SMME] + ia_ssa: [1] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml deleted file mode 100644 index a72cc5f3689..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.yaml +++ /dev/null @@ -1,227 +0,0 @@ -- name: Case 1, blind aged Iowan receives flat 22 dollar supplement plus federal SSI. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 40 - is_blind: true - employment_income: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - is_ssi_eligible: [true] - ssi: [967] - ia_ssa_eligible: [true] - ia_ssa_category: [BLIND] - ia_ssa_blind_supplement: [22] - ia_ssa: [22] - -- name: Case 2, non-blind aged Iowan receives no blind supplement. - period: 2025-01 - input: - people: - person1: - age: 70 - is_blind: false - employment_income: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_blind_supplement: [0] - -- name: Case 3, blind person with excess resources receives no supplement. - period: 2025-01 - input: - people: - person1: - age: 40 - is_blind: true - employment_income: 0 - ssi_countable_resources: 5_000 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false - ia_ssa_resources_eligible: [false] - ia_ssa_eligible: [false] - ia_ssa_blind_supplement: [0] - -- name: Case 4, blind RCF resident receives zero blind supplement (IAC 441-52.1(4) exclusivity). - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - is_blind: true - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 37.60 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Per IAC 441-52.1(4), blind supplement only paid if not receiving - # another type of SSA. RCF category wins -> blind supplement is $0. - ia_ssa_category: [RCF] - ia_ssa_blind_supplement: [0] - -- name: Case 5, blind Iowan with earnings still gets blind supplement. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 40 - is_blind: true - # Earned income: $500/mo; after blind/disabled working student? - # The blind supplement has no income test at the category level - # beyond SSI categorical eligibility (which ignores income). - employment_income: 6_000 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Still ssi_eligible (passes ABD + resources + immigration). - is_ssi_eligible: [true] - ia_ssa_eligible: [true] - ia_ssa_category: [BLIND] - ia_ssa_blind_supplement: [22] - -- name: Case 6, blind person at 2026 still receives frozen 22 dollar supplement. - period: 2026-01 - input: - people: - person1: - age: 40 - is_blind: true - employment_income: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Blind supplement frozen at $22 since 2017. - ia_ssa_blind_supplement: [22] - -- name: Case 7, blind person with income above FBR plus state standard gets zero supplement. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - is_blind: true - social_security_retirement: 14_400 # $1,200/mo gross - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # $1,200/mo SS gross -> $1,180/mo countable (after $20 disregard). - # FBR $967, blind state standard $22, total $989. Countable $1,180 - # exceeds $989 -> blind income gate in ia_ssa_category excludes, so - # category drops to NONE and supplement is $0. - ia_ssa_category: [NONE] - ia_ssa_blind_supplement: [0] - -- name: Case 8, blind person with income just above FBR gets partial supplement. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - is_blind: true - social_security_retirement: 12_000 # $1,000/mo gross - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # $1,000/mo SS gross -> $980/mo countable (after $20 disregard). - # FBR $967, blind state standard $22, total $989. - # Federally-administered formula: max(0, 989 - max(980, 967)) = 9. - ia_ssa_category: [BLIND] - ia_ssa_blind_supplement: [9] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml deleted file mode 100644 index 41c22be146a..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_dp_supplement.yaml +++ /dev/null @@ -1,244 +0,0 @@ -# IAC 441—52.1(2): DP is federally-administered per POMS SI 01415.050.F. -# Federally-administered SSP formula: -# supplement = max(0, payment_standard - max(countable, FBR)) -# capped at max_per_person_cap ($503 in 2025, $518 in 2026). -# Also requires dependent's countable income < dependent_income_limit. - -- name: Case 1, person with no DP configuration gets zero supplement. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_dp_configuration: NONE - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_dp_supplement: [0] - -- name: Case 2, person with excess resources gets zero DP supplement. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ssi_countable_resources: 5_000 - ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false - ia_ssa_eligible: [false] - ia_ssa_dp_supplement: [0] - -- name: Case 3, DP supplement capped at per-person maximum 503 dollars. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Standard $1,997 minus federal SSI and income; well above $503 cap - ia_ssa_dp_supplement: [503] - -- name: Case 4, DP supplement cap rises to 518 dollars in 2026. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_dp_supplement: [518] - -- name: Case 5, aged client with aged spouse and dependent child integration. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 0 - person2: - age: 68 - employment_income: 0 - ia_ssa_dp_configuration: NONE - person3: - age: 10 - employment_income: 0 - marital_units: - first_marital_unit: - members: [person1, person2] - second_marital_unit: - members: [person3] - tax_units: - tax_unit: - members: [person1, person2, person3] - spm_units: - spm_unit: - members: [person1, person2, person3] - households: - household: - members: [person1, person2, person3] - state_code: IA - output: - # person1: DP capped at $503. - # person2: income above 120% FPL for household of 3 would be required - # for SMME ($26,650 × 1.2 / 12 = $2,665/mo); but income is $0, so not - # SMME-eligible -> NONE. - # person3: child -> NONE. - ia_ssa_category: [DP, NONE, NONE] - ia_ssa_dp_supplement: [503, 0, 0] - -- name: Case 6, dependent income above limit disqualifies DP supplement. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 600 # > $503 limit - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Dependent income exceeds the limit -> DP category gate fails. Person - # is 70 with no other qualifying category -> NONE -> supplement 0. - ia_ssa_category: [NONE] - ia_ssa_dp_supplement: [0] - -- name: Case 7, 2017 DP aged-or-disabled-with-dependent uses 1114 dollar standard and 379 dollar cap. - period: 2017-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # 2017 AGED_OR_DISABLED_WITH_DEPENDENT payment standard $1,114; FBR $735; - # max_per_person_cap $379. Federally-administered formula: - # max(0, 1114 - max(0, 735)) = $379 -> capped at $379. - ia_ssa_category: [DP] - ia_ssa_dp_supplement: [379] - -- name: Case 8, DP supplement phases down when countable income exceeds FBR. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 20_640 # $1,720/mo - ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT - ia_ssa_dp_has_eligible_dependent: true - ia_ssa_dp_dependent_countable_income: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # $1,720/mo SS gross -> $1,700/mo countable. Payment standard $1,997, - # FBR $967. Federally-administered formula: - # max(0, 1997 - max(1700, 967)) = $297 (under the $503 cap). - ia_ssa_dp_supplement: [297] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml deleted file mode 100644 index 3cb7ac886c4..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_flh_supplement.yaml +++ /dev/null @@ -1,167 +0,0 @@ -# IAC 441—52.1(1): FLH is federally-administered per POMS SI 01415.050.F. -# Federally-administered SSP formula: -# supplement = max(0, assistance_standard - max(countable, FBR)) -# capped at max_supplement ($142). - -- name: Case 1, aged FLH resident with zero income (federal SSI plus capped state supplement). - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_family_life_home: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Federal SSI fills to FBR $967; assistance standard $1,129; - # raw supplement = 1,129 - max(0, 967) = 162; capped at $142. - is_ssi_eligible: [true] - ssi: [967] - ia_ssa_eligible: [true] - ia_ssa_category: [FLH] - ia_ssa_flh_supplement: [142] - ia_ssa: [142] - -- name: Case 2, person not in FLH receives zero FLH supplement. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_family_life_home: false - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_flh_supplement: [0] - -- name: Case 3, FLH resident with excess resources receives zero. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ssi_countable_resources: 5_000 - ia_ssa_resides_in_family_life_home: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false - ia_ssa_eligible: [false] - ia_ssa_flh_supplement: [0] - -- name: Case 4, FLH resident 2026 still capped at 142 dollars. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_family_life_home: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Cap is frozen at $142 even though standard and PNA rise in 2026 - ia_ssa_flh_supplement: [142] - -- name: Case 5, FLH supplement phases down when countable income exceeds FBR. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 12_840 # $1,070/mo gross - ia_ssa_resides_in_family_life_home: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # $1,070/mo SS gross -> $1,050/mo countable (after $20 disregard). - # Assistance standard $1,129; FBR $967. - # max(0, 1129 - max(1050, 967)) = $79 (under the $142 cap). - ia_ssa_flh_supplement: [79] - -- name: Case 6, FLH supplement is zero when countable income equals or exceeds standard. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 14_400 # $1,200/mo gross - ia_ssa_resides_in_family_life_home: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Countable $1,180/mo; standard $1,129; raw = max(0, 1129 - 1180) = 0. - ia_ssa_flh_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml deleted file mode 100644 index 7c5ec01f6d1..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_supplement.yaml +++ /dev/null @@ -1,348 +0,0 @@ -# IAC 441—177.10(2)(a): payment = max(0, min(cost, per-person cap) - -# client participation), where client participation is marital-unit -# countable income minus the basic SSI standard disregard (the applicable -# FBR for a single or joint claim), split evenly across the marital unit. -# IAC 441—177.10(3): IHHRC max benefit payable is $480.55 per person, inclusive -# of all services for all providers. The $961.10 in 441—177.4(1)(f) is the -# combined couple income cap, NOT a per-person payment cap. -# IAC 441—177.4(1)(c): recipient must live in own home (not in RCF or FLH). -# IAC 441—177.4(1)(f): income cap on countable income after the basic SSI -# standard disregard — individual <= $480.55, or combined couple <= $961.10 -# when both spouses need care. - -- name: Case 1, individual IHHRC cost below max pays actual cost. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 450 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Cost $450 below max $480.55 -> pays actual $450 - ia_ssa_ihhrc_supplement: [450] - -- name: Case 2, individual IHHRC cost above max is capped at 480.55 dollars. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 600 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Cost $600 > max $480.55 -> capped - ia_ssa_ihhrc_supplement: [480.55] - -- name: Case 3, person not needing IHHRC receives zero supplement. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: false - ia_ssa_ihhrc_cost_of_care: 400 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_ihhrc_supplement: [0] - -- name: Case 4, person needing IHHRC with excess resources receives zero. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ssi_countable_resources: 5_000 - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 400 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false - ia_ssa_eligible: [false] - ia_ssa_ihhrc_supplement: [0] - -- name: Case 5, couple both needing IHHRC use couple cap. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 900 - person2: - age: 68 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 900 - marital_units: - marital_unit: - members: [person1, person2] - tax_units: - tax_unit: - members: [person1, person2] - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: IA - output: - # Both need care -> combined income cap $961.10 (combined countable = 0). - # Payment max is $480.55 per person (441—177.10(3)). - # Each cost $900 > per-person max $480.55 -> capped at $480.55 each. - ia_ssa_ihhrc_both_need_care: [true, true] - ia_ssa_ihhrc_supplement: [480.55, 480.55] - -- name: Case 6, couple both needing IHHRC with high cost capped at 480.55 dollars per person. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 1_500 - person2: - age: 68 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 1_500 - marital_units: - marital_unit: - members: [person1, person2] - tax_units: - tax_unit: - members: [person1, person2] - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: IA - output: - # Both need care -> combined income cap $961.10 (combined countable = 0). - # Payment max is $480.55 per person (441—177.10(3)). - # Each cost $1,500 > per-person max $480.55 -> capped at $480.55 each. - ia_ssa_ihhrc_supplement: [480.55, 480.55] - -- name: Case 7, couple with only one spouse needing IHHRC uses single cap. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 800 - person2: - age: 68 - employment_income: 0 - ia_ssa_needs_in_home_health_related_care: false - ia_ssa_ihhrc_cost_of_care: 0 - marital_units: - marital_unit: - members: [person1, person2] - tax_units: - tax_unit: - members: [person1, person2] - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: IA - output: - # Only person1 needs care -> both_need_care false -> single cap $480.55 - ia_ssa_ihhrc_both_need_care: [false, false] - ia_ssa_ihhrc_supplement: [480.55, 0] - -- name: Case 8, person with countable income above single cap is ineligible. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 20_000 # $1,667/mo gross - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 400 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Countable $1,647/mo minus individual FBR disregard $967 = $680, which - # exceeds the single cap $480.55 -> not in IHHRC category -> no supplement. - ia_ssa_ihhrc_supplement: [0] - -- name: Case 9, single person with countable income below FBR gets full supplement. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 9_600 # $800/mo gross - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 400 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # $800/mo SS gross, countable $780/mo. Individual FBR disregard $967 makes - # income after disregard 0 -> passes single cap. Client participation is - # 0 -> supplement equals cost $400. - ia_ssa_ihhrc_supplement: [400] - -- name: Case 10, couple both needing IHHRC with combined countable below couple FBR. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 7_200 # $600/mo gross - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 400 - person2: - age: 68 - social_security_retirement: 7_200 # $600/mo gross - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 400 - marital_units: - marital_unit: - members: [person1, person2] - tax_units: - tax_unit: - members: [person1, person2] - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: IA - output: - # Each spouse's countable unearned is about $580/mo after the $20 general - # disregard, combined ~$1,160. Couple FBR disregard $1,450 leaves 0 after - # disregard -> passes couple cap $961.10. Client participation is 0 -> - # each person's supplement equals cost $400. - ia_ssa_ihhrc_both_need_care: [true, true] - ia_ssa_ihhrc_supplement: [400, 400] - -- name: Case 11, couple both needing IHHRC with combined countable above couple cap. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 15_840 # $1,320/mo gross - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 400 - person2: - age: 68 - social_security_retirement: 15_840 # $1,320/mo gross - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 400 - marital_units: - marital_unit: - members: [person1, person2] - tax_units: - tax_unit: - members: [person1, person2] - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: IA - output: - # Each spouse's countable ~$1,300/mo; combined ~$2,600. After couple FBR - # disregard $1,450 -> $1,150 countable, which exceeds the couple cap - # $961.10 -> both ineligible. - ia_ssa_ihhrc_both_need_care: [true, true] - ia_ssa_ihhrc_supplement: [0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml similarity index 93% rename from policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml rename to policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml index 5f59bf5ca34..56bf8910c0c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml @@ -1,4 +1,4 @@ -# Verifies ia_ssa_category priority ordering: +# Verifies ia_ssa_living_arrangement priority ordering: # RCF > IHHRC > FLH > DP > BLIND > SMME > NONE # # Note: SMME requires income > 120% FPL (IAC 441—51.6(6)). 2025 FPL 1-person @@ -30,7 +30,7 @@ state_code: IA output: # RCF outranks BLIND - ia_ssa_category: [RCF] + ia_ssa_living_arrangement: [RCF] - name: Case 2, FLH resident who is also blind gets FLH category not BLIND. period: 2025-01 @@ -56,7 +56,7 @@ state_code: IA output: # FLH outranks BLIND - ia_ssa_category: [FLH] + ia_ssa_living_arrangement: [FLH] - name: Case 3, aged person above 120% FPL with Medicaid and Part B gets SMME. period: 2025-01 @@ -83,7 +83,7 @@ state_code: IA output: # No other category applies; income above 120% FPL -> SMME - ia_ssa_category: [SMME] + ia_ssa_living_arrangement: [SMME] - name: Case 4, person in no qualifying category gets NONE. period: 2025-01 @@ -109,7 +109,7 @@ members: [person1] state_code: IA output: - ia_ssa_category: [NONE] + ia_ssa_living_arrangement: [NONE] - name: Case 5, FLH resident who also needs IHHRC gets FLH (IAC 441-177.4(1)(c) own-home rule). period: 2025-01 @@ -137,7 +137,7 @@ state_code: IA output: # IHHRC requires living in own home; FLH resident fails that check -> FLH wins - ia_ssa_category: [FLH] + ia_ssa_living_arrangement: [FLH] - name: Case 6, person needing IHHRC who is also blind gets IHHRC not BLIND. period: 2025-01 @@ -165,7 +165,7 @@ state_code: IA output: # IHHRC outranks BLIND - ia_ssa_category: [IHHRC] + ia_ssa_living_arrangement: [IHHRC] - name: Case 7, person needing IHHRC with DP configuration gets IHHRC not DP. period: 2025-01 @@ -194,7 +194,7 @@ state_code: IA output: # IHHRC outranks DP - ia_ssa_category: [IHHRC] + ia_ssa_living_arrangement: [IHHRC] - name: Case 8, person with DP configuration who is also blind gets DP not BLIND. period: 2025-01 @@ -221,7 +221,7 @@ state_code: IA output: # DP outranks BLIND - ia_ssa_category: [DP] + ia_ssa_living_arrangement: [DP] - name: Case 9, blind person with SMME-range income falls to SMME not BLIND. period: 2025-01 @@ -252,7 +252,7 @@ # BLIND branch skipped. SMME income floor is 120% FPL ($1,565); $1,980 > # $1,565 -> SMME applies. BLIND and SMME income ranges are disjoint, so # priority ordering between them is academic. - ia_ssa_category: [SMME] + ia_ssa_living_arrangement: [SMME] - name: Case 10, DP-configured person with SMME-eligible income gets DP not SMME. period: 2025-01 @@ -281,7 +281,7 @@ state_code: IA output: # DP outranks SMME - ia_ssa_category: [DP] + ia_ssa_living_arrangement: [DP] - name: Case 11, IHHRC person with SMME-eligible income gets IHHRC not SMME. period: 2025-01 @@ -315,7 +315,7 @@ output: # IHHRC outranks SMME (SMME not active here — income $0 below 120% FPL — # but the priority order still applies even if SMME were active). - ia_ssa_category: [IHHRC] + ia_ssa_living_arrangement: [IHHRC] - name: Case 12, blind person with DP configuration and over-income dependent falls to BLIND. period: 2025-01 @@ -344,7 +344,7 @@ state_code: IA output: # Dependent income $600 exceeds the $503 2025 dependent income limit, so - # the DP category gate fails. Person is blind with $0 countable (< FBR + + # the DP living-arrangement gate fails. Person is blind with $0 countable (< FBR + # blind standard) -> falls through to BLIND category. - ia_ssa_category: [BLIND] - ia_ssa_dp_supplement: [0] + ia_ssa_living_arrangement: [BLIND] + ia_ssa: [22] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml deleted file mode 100644 index a877781aaa4..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_rcf_supplement.yaml +++ /dev/null @@ -1,262 +0,0 @@ -# IAC 441—52.1(3): payment in RCF = (31 * max_per_diem) - client_participation -# where client_participation = total_monthly_income - personal_needs_allowance. -# Total income = SSI-countable income + federal SSI payment. -# RCF income eligibility: client_participation < 31 * max_per_diem. - -- name: Case 1, aged RCF resident with no income (SSI fills to FBR). - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 37.60 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Federal SSI fills to 2025 FBR $967; RCF supplement = - # 31 * $37.60 - ($967 - $126) = $1,165.60 - $841 = $324.60 - is_ssi_eligible: [true] - ssi: [967] - ia_ssa_eligible: [true] - ia_ssa_category: [RCF] - ia_ssa_rcf_supplement: [324.60] - ia_ssa: [324.60] - -- name: Case 2, RCF per diem above max is capped at 37.60 dollars per day. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 50 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Capped cost = 31 * $37.60 = $1,165.60; CP $841; supplement $324.60 - ia_ssa_rcf_supplement: [324.60] - -- name: Case 3, person not in RCF receives zero supplement. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: false - ia_ssa_rcf_cost_per_diem: 30 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_rcf_supplement: [0] - -- name: Case 4, aged RCF resident in 2026 uses higher 38.47 dollar per diem. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 38.47 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Federal SSI fills to 2026 FBR $994; RCF supplement = - # 31 * $38.47 - ($994 - $130) = $1,192.57 - $864 = $328.57 - is_ssi_eligible: [true] - ssi: [994] - ia_ssa_category: [RCF] - ia_ssa_rcf_supplement: [328.57] - -- name: Case 5, RCF resident with zero reported per diem receives zero. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 0 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # cost_of_care = 0; max(0, 0 - client_participation) = 0 - ia_ssa_rcf_supplement: [0] - -- name: Case 6, RCF resident with 12000 dollar Social Security has higher client participation. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 12_000 # $1,000/mo - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 37.60 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # $1,000/mo SS, countable $980; no SSI (countable > FBR minus $0 state - # standard); total monthly income $980; client participation - # $980 - $126 = $854; supplement = $1,165.60 - $854 = $311.60. - ia_ssa_rcf_supplement: [311.60] - -- name: Case 7, RCF resident with income above 31 times max per diem is ineligible. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 30_000 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 37.60 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # SS $2,500/mo exceeds SSI FBR; client participation > - # 31 * $37.60 income limit -> not in RCF category -> no supplement - ia_ssa_rcf_supplement: [0] - -- name: Case 8, 2018 RCF resident uses the 99 dollar PNA effective March 2018. - period: 2018-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 30.60 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Federal SSI fills to 2018 FBR $750. 2018 RCF: max_per_diem $30.60, - # PNA $99 (per March 28, 2018 IAC rule update). CP $750 - $99 = $651. - # Cost of care 31 * $30.60 = $948.60. Supplement $948.60 - $651 = $297.60. - ssi: [750] - ia_ssa_category: [RCF] - ia_ssa_rcf_supplement: [297.60] - -- name: Case 9, RCF resident with excess resources receives zero supplement. - period: 2025-01 - input: - people: - person1: - age: 70 - employment_income: 0 - ssi_countable_resources: 5_000 - ia_ssa_resides_in_residential_care_facility: true - ia_ssa_rcf_cost_per_diem: 37.60 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Resources $5,000 > $2,000 limit -> ia_ssa_eligible false - ia_ssa_eligible: [false] - ia_ssa_rcf_supplement: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml deleted file mode 100644 index 3bdef0fc27f..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_smme_supplement.yaml +++ /dev/null @@ -1,211 +0,0 @@ -# SMME is a $1/month technical SSP pathway for people who meet all SSI -# categorical eligibility (aged/blind/disabled, resources, immigration) but -# whose income exceeds the federal SSI benefit rate. Per IAC 441—51.7(6), -# income must exceed 120% of the federal poverty level. 2025 FPL (1 person, -# contiguous US) = $15,650; 120% = $18,780/year or $1,565/month. - -- name: Case 1, aged Iowan with income above 120% FPL, full Medicaid and Part B. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 24_000 # $2,000/month - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Income $2,000/mo; countable $1,980 after $20 exclusion; - # 120% FPL for 1 person (2025, contiguous) = $1,565/mo; exceeds threshold. - # No SSI (countable > FBR $967). SMME pays $1. - is_ssi_eligible: [true] - ssi: [0] - ia_ssa_eligible: [true] - ia_ssa_category: [SMME] - ia_ssa_smme_supplement: [1] - ia_ssa: [1] - -- name: Case 2, aged Iowan with low income (below 120% FPL) is not SMME-eligible. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 12_000 # $1,000/month - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Income $1,000/mo; countable $980 after $20 exclusion; below 120% FPL - # $1,565/mo. SMME-ineligible; person gets regular SSI instead - # (FBR $967 - countable $980 < 0, so no federal SSI either). - ia_ssa_category: [NONE] - ia_ssa_smme_supplement: [0] - -- name: Case 3, aged Iowan without full Medicaid gets no SMME. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 24_000 - ia_ssa_has_full_medicaid: false - ia_ssa_has_medicare_part_b: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_category: [NONE] - ia_ssa_smme_supplement: [0] - -- name: Case 4, aged Iowan without Medicare Part B gets no SMME. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 24_000 - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: false - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_category: [NONE] - ia_ssa_smme_supplement: [0] - -- name: Case 5, person with excess resources receives zero SMME. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - social_security_retirement: 24_000 - ssi_countable_resources: 5_000 - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Resources $5,000 > single limit $2,000 -> ia_ssa_resources_eligible false - ia_ssa_eligible: [false] - ia_ssa_smme_supplement: [0] - -- name: Case 6, income exactly at 120% FPL boundary is not SMME-eligible. - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - # $18,780/year gross = $1,565/month; countable = $1,545 after $20 - # exclusion, which is below the $1,565 threshold. Boundary check. - social_security_retirement: 18_780 - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # Statute requires income to EXCEED 120% FPL (>, not >=). - ia_ssa_category: [NONE] - ia_ssa_smme_supplement: [0] - -- name: Case 7, aged Iowan at 2026 rates with income above 120% FPL. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - # 2026 FPL (1 person, contiguous) = $15,960; 120% = $19,152/year. - social_security_retirement: 30_000 # $2,500/month, well above threshold - ia_ssa_has_full_medicaid: true - ia_ssa_has_medicare_part_b: true - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - ia_ssa_category: [SMME] - ia_ssa_smme_supplement: [1] - ia_ssa: [1] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py deleted file mode 100644 index d0fb4e808e6..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/dp/ia_ssa_dp_supplement.py +++ /dev/null @@ -1,33 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_dp_supplement(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Iowa SSA dependent person supplement" - unit = USD - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1", - "https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance", - ) - - def formula(person, period, parameters): - category = person("ia_ssa_category", period) - in_category = category == category.possible_values.DP - p = parameters(period).gov.states.ia.hhs.ssa - configuration = person("ia_ssa_dp_configuration", period) - payment_standard = p.dp.assistance_standard[configuration] - # Iowa DP is federally-administered per POMS SI 01415.050.F. For - # federally-administered SSP, the state supplement equals - # max(0, total_standard − max(countable_income, FBR)): it stays at - # the full state amount while income is below the FBR and then phases - # down dollar-for-dollar as income rises above the FBR. - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR - ) - fbr = parameters(period).gov.ssa.ssi.amount.individual - raw_supplement = max_(0, payment_standard - max_(countable_monthly, fbr)) - capped_supplement = min_(raw_supplement, p.dp.max_per_person_cap) - return in_category * capped_supplement diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py deleted file mode 100644 index 0cdf69d4ae0..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_flh_supplement.py +++ /dev/null @@ -1,30 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_flh_supplement(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Iowa SSA family-life home supplement" - unit = USD - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" - ) - - def formula(person, period, parameters): - category = person("ia_ssa_category", period) - in_category = category == category.possible_values.FLH - p = parameters(period).gov.states.ia.hhs.ssa - # Iowa FLH is federally-administered per POMS SI 01415.050.F. For - # federally-administered SSP, the state supplement equals - # max(0, total_standard − max(countable_income, FBR)). - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR - ) - fbr = parameters(period).gov.ssa.ssi.amount.individual - raw_supplement = max_( - 0, p.flh.assistance_standard - max_(countable_monthly, fbr) - ) - capped_supplement = min_(raw_supplement, p.flh.max_supplement) - return in_category * capped_supplement diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index ca32d2625a8..8a7e37c3ae0 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -14,11 +14,70 @@ class ia_ssa(Variable): "https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance", ) - adds = [ - "ia_ssa_blind_supplement", - "ia_ssa_dp_supplement", - "ia_ssa_flh_supplement", - "ia_ssa_ihhrc_supplement", - "ia_ssa_rcf_supplement", - "ia_ssa_smme_supplement", - ] + def formula(person, period, parameters): + arrangement = person("ia_ssa_living_arrangement", period) + arr_values = arrangement.possible_values + p = parameters(period).gov.states.ia.hhs.ssa + # Monthly income helpers. + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR + total_rcf_income = countable_monthly + ssi_monthly + individual_fbr = parameters(period).gov.ssa.ssi.amount.individual + couple_fbr = parameters(period).gov.ssa.ssi.amount.couple + joint_claim = person("ssi_claim_is_joint", period.this_year) + basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) + # Federally-administered SSP V-shape: + # supplement = max(0, (FBR + state_standard) − max(countable, FBR)) + # Per POMS SI 01415.050.F, applied to Blind, DP, FLH. + countable_or_fbr = max_(countable_monthly, individual_fbr) + # BLIND — IAC 441—52.1(4): flat state standard ($22 frozen since 2011). + blind_amt = max_(0, (individual_fbr + p.blind) - countable_or_fbr) + # DP — IAC 441—52.1(2): configuration-keyed standard, capped per person. + dp_config = person("ia_ssa_dp_configuration", period) + dp_standard = p.dp.assistance_standard[dp_config] + dp_raw = max_(0, dp_standard - countable_or_fbr) + dp_amt = min_(dp_raw, p.dp.max_per_person_cap) + # FLH — IAC 441—52.1(1): the assistance_standard is the total + # standard (already includes the FBR portion), capped at + # max_supplement. + flh_raw = max_(0, p.flh.assistance_standard - countable_or_fbr) + flh_amt = min_(flh_raw, p.flh.max_supplement) + # RCF — IAC 441—52.1(3): cost-of-care minus client participation. + # Client participation = total monthly income (SSI countable + federal + # SSI payment) minus the personal needs allowance. + rcf_per_diem = person("ia_ssa_rcf_cost_per_diem", period) + rcf_capped_per_diem = min_(rcf_per_diem, p.rcf.max_per_diem) + rcf_cost_of_care = rcf_capped_per_diem * p.rcf.days_multiplier + rcf_client_participation = max_( + 0, total_rcf_income - p.rcf.personal_needs_allowance + ) + rcf_amt = max_(0, rcf_cost_of_care - rcf_client_participation) + # IHHRC — IAC 441—177.10(2)(a) and 177.10(3): + # payment = max(0, min(cost, per-person cap) − client participation). + # Client participation is combined marital-unit countable income + # after the basic SSI standard disregard (the applicable FBR for a + # single or joint claim), split evenly across marital-unit members. + ihhrc_cost = person("ia_ssa_ihhrc_cost_of_care", period) + combined_countable = person.marital_unit.sum(countable_monthly) + combined_participation = max_(0, combined_countable - basic_ssi_disregard) + ihhrc_client_participation = ( + combined_participation / person.marital_unit.nb_persons() + ) + ihhrc_eligible_cost = min_(ihhrc_cost, p.ihhrc.max_cost_single) + ihhrc_amt = max_(0, ihhrc_eligible_cost - ihhrc_client_participation) + # SMME — IAC 441—52.1(7): flat amount ($1 since 2017). + smme_amt = p.smme.amount + return select( + [ + arrangement == arr_values.RCF, + arrangement == arr_values.IHHRC, + arrangement == arr_values.FLH, + arrangement == arr_values.DP, + arrangement == arr_values.BLIND, + arrangement == arr_values.SMME, + ], + [rcf_amt, ihhrc_amt, flh_amt, dp_amt, blind_amt, smme_amt], + default=0, + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py deleted file mode 100644 index bcf967fefcb..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_blind_supplement.py +++ /dev/null @@ -1,29 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_blind_supplement(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Iowa SSA blind supplement" - unit = USD - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2" - ) - - def formula(person, period, parameters): - category = person("ia_ssa_category", period) - in_category = category == category.possible_values.BLIND - p = parameters(period).gov.states.ia.hhs.ssa - # Iowa blind is federally-administered per POMS SI 01415.050.F. For - # federally-administered SSP, the state supplement equals - # max(0, total_standard − max(countable_income, FBR)): it stays at the - # full state amount while income is below the FBR and then phases down - # dollar-for-dollar as income rises above the FBR. - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR - ) - fbr = parameters(period).gov.ssa.ssi.amount.individual - raw_supplement = max_(0, (fbr + p.blind) - max_(countable_monthly, fbr)) - return in_category * raw_supplement diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py similarity index 85% rename from policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py rename to policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py index 5de9b84c0d6..ae4a679a1ce 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py @@ -1,7 +1,7 @@ from policyengine_us.model_api import * -class IASSACategory(Enum): +class IASSALivingArrangement(Enum): RCF = "Residential care facility" IHHRC = "In-home health-related care" FLH = "Family-life home" @@ -11,13 +11,13 @@ class IASSACategory(Enum): NONE = "Not in an Iowa SSA category" -class ia_ssa_category(Variable): +class ia_ssa_living_arrangement(Variable): value_type = Enum entity = Person definition_period = MONTH - label = "Iowa SSA category" - possible_values = IASSACategory - default_value = IASSACategory.NONE + label = "Iowa SSA living arrangement" + possible_values = IASSALivingArrangement + default_value = IASSALivingArrangement.NONE defined_for = StateCode.IA reference = "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf" @@ -72,9 +72,10 @@ def formula(person, period, parameters): dp_configuration = person("ia_ssa_dp_configuration", period) in_dp = dp_configuration != dp_configuration.possible_values.NONE # IAC 441—52.1(2): DP requires the dependent's countable income to be - # below the dependent income limit. Gate DP at the category level so - # people who qualify for DP but fail the dependent-income test fall - # through to Blind / SMME rather than receiving a zero DP supplement. + # below the dependent income limit. Gate DP at the living-arrangement + # level so people who qualify for DP but fail the dependent-income + # test fall through to Blind / SMME rather than receiving a zero DP + # supplement. dependent_income = person("ia_ssa_dp_dependent_countable_income", period) dependent_income_eligible = dependent_income < p.dp.dependent_income_limit is_blind = person("is_blind", period.this_year) @@ -94,12 +95,12 @@ def formula(person, period, parameters): eligible & smme_eligible, ], [ - IASSACategory.RCF, - IASSACategory.IHHRC, - IASSACategory.FLH, - IASSACategory.DP, - IASSACategory.BLIND, - IASSACategory.SMME, + IASSALivingArrangement.RCF, + IASSALivingArrangement.IHHRC, + IASSALivingArrangement.FLH, + IASSALivingArrangement.DP, + IASSALivingArrangement.BLIND, + IASSALivingArrangement.SMME, ], - default=IASSACategory.NONE, + default=IASSALivingArrangement.NONE, ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py deleted file mode 100644 index 89447da1a09..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_supplement.py +++ /dev/null @@ -1,42 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_ihhrc_supplement(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Iowa SSA in-home health-related care supplement" - unit = USD - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2" - ) - - def formula(person, period, parameters): - category = person("ia_ssa_category", period) - in_category = category == category.possible_values.IHHRC - p = parameters(period).gov.states.ia.hhs.ssa - cost = person("ia_ssa_ihhrc_cost_of_care", period) - # IAC 441—177.10(2)(a): payment equals cost of care (capped per person - # at the single cap from 441—177.10(3)) minus client participation, - # where client participation is countable income after the basic SSI - # standard disregard (the applicable FBR for a single or joint claim). - # Compute participation at the marital-unit level and split evenly - # across members so the aggregated SPM-unit total is correct without - # double-counting. - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR - ) - individual_fbr = parameters(period).gov.ssa.ssi.amount.individual - couple_fbr = parameters(period).gov.ssa.ssi.amount.couple - joint_claim = person("ssi_claim_is_joint", period.this_year) - disregard = where(joint_claim, couple_fbr, individual_fbr) - combined_countable = person.marital_unit.sum(countable_monthly) - combined_participation = max_(0, combined_countable - disregard) - # Split evenly across marital-unit members (1 person unmarried, 2 if - # married) so the person-level values sum back to the combined total. - client_participation = combined_participation / person.marital_unit.nb_persons() - # IAC 441—177.10(3): maximum benefit payable is $480.55 per client, - # inclusive of all services for all providers. - eligible_cost = min_(cost, p.ihhrc.max_cost_single) - return in_category * max_(0, eligible_cost - client_participation) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py deleted file mode 100644 index e893d77cdeb..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_rcf_supplement.py +++ /dev/null @@ -1,33 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_rcf_supplement(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Iowa SSA residential care facility supplement" - unit = USD - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" - ) - - def formula(person, period, parameters): - category = person("ia_ssa_category", period) - in_category = category == category.possible_values.RCF - p = parameters(period).gov.states.ia.hhs.ssa - cost_per_diem = person("ia_ssa_rcf_cost_per_diem", period) - capped_per_diem = min_(cost_per_diem, p.rcf.max_per_diem) - cost_of_care = capped_per_diem * p.rcf.days_multiplier - # Iowa RCF client participation is "total monthly income minus the - # personal needs allowance" per IAC 441—52.1. Use SSI countable income - # plus the federal SSI payment as the monthly income proxy. - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR - ) - ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR - total_rcf_income = countable_monthly + ssi_monthly - client_participation = max_( - 0, total_rcf_income - p.rcf.personal_needs_allowance - ) - return in_category * max_(0, cost_of_care - client_participation) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py deleted file mode 100644 index d07445d9d8d..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_supplement.py +++ /dev/null @@ -1,19 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_smme_supplement(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Iowa SSA SMME supplement" - unit = USD - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2" - ) - - def formula(person, period, parameters): - category = person("ia_ssa_category", period) - in_category = category == category.possible_values.SMME - p = parameters(period).gov.states.ia.hhs.ssa - return in_category * p.smme.amount From 7932788f7ace3ae8fb06a6b3992d0726609d70ee Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 23 Apr 2026 00:43:57 -0400 Subject: [PATCH 13/23] Store Iowa SSA DP and FLH standards as state-only; apply P2 fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parameter normalization: - Rename dp/assistance_standard.yaml -> dp/state_supplement.yaml - Rename flh/assistance_standard.yaml -> flh/state_supplement.yaml - Values are now the state portion above FBR (consistent with blind.yaml), so all three federally-administered arrangements use one formula shape: max(0, (FBR + state_supplement) - max(countable, FBR)). P2 #1 — FLH Department top-up for SSI-only recipients: The Iowa FLH state supplement ($162 from 2017 onward) exceeds the federally-administered max_supplement cap ($142) by exactly $20, the SSI general-income disregard. Per IAC 441-52.1(1), when the recipient has no other income (so SSA's $20 disregard is unused), Iowa HHS issues an additional Department payment equal to (state_supplement - max_supplement) to close the gap and bring total income to the full standard. In 2011 the state supplement equals the cap so no top-up is owed; from 2017 onward the top-up is $20. P2 #2 — IHHRC client participation charged to sole recipient: When only one spouse needs IHHRC, charge the entire combined client participation to that spouse instead of splitting it evenly across the marital unit. The split remains correct for both-need-care couples where both members compute the supplement independently. Tests: - FLH Cases 1 and 4 (zero-income) now expect $162 (was $142) - New IHHRC Case 12 exercises the sole-recipient participation rule: couple with $800/mo SS each, one needs care -> supplement $270 instead of $335 under the old 50/50 split. 77 + 1 = 78 Iowa SSA tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...ce_standard.yaml => state_supplement.yaml} | 69 +++++++++--------- ...ce_standard.yaml => state_supplement.yaml} | 16 ++-- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 73 ++++++++++++++++--- .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 55 +++++++++----- 4 files changed, 142 insertions(+), 71 deletions(-) rename policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/{assistance_standard.yaml => state_supplement.yaml} (51%) rename policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/{assistance_standard.yaml => state_supplement.yaml} (72%) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml similarity index 51% rename from policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml rename to policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml index f07c823a37f..9e4137b9a41 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml @@ -1,9 +1,9 @@ -description: Iowa provides this amount as the dependent person assistance standard under the State Supplementary Assistance program. +description: Iowa provides this state supplement amount above the federal SSI benefit rate (FBR) for dependent person configurations under the State Supplementary Assistance program. metadata: unit: currency-USD period: month - label: Iowa SSA dependent person assistance standard + label: Iowa SSA dependent person state supplement breakdown: - ia_ssa_dp_configuration reference: @@ -21,42 +21,43 @@ metadata: href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance AGED_OR_DISABLED_WITH_DEPENDENT: - 2011-01-01: 1_018 - 2017-01-01: 1_114 - 2018-01-01: 1_137 - 2025-01-01: 1_470 - 2026-01-01: 1_512 + 2011-01-01: 344 + 2017-01-01: 379 + 2018-01-01: 387 + 2025-01-01: 503 + 2026-01-01: 518 AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT: - 2011-01-01: 1_355 - 2017-01-01: 1_482 - 2018-01-01: 1_512 - 2025-01-01: 1_953 - 2026-01-01: 2_009 + 2011-01-01: 681 + 2017-01-01: 747 + 2018-01-01: 762 + 2025-01-01: 986 + 2026-01-01: 1_015 BLIND_WITH_DEPENDENT: - 2011-01-01: 1_040 - 2017-01-01: 1_136 - 2018-01-01: 1_159 - 2025-01-01: 1_492 - 2026-01-01: 1_534 + 2011-01-01: 366 + 2017-01-01: 401 + 2018-01-01: 409 + 2025-01-01: 525 + 2026-01-01: 540 BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: - # 2011: SSA Table 1 shows both-blind couple $1,399; footnote a reduces by $22 - # when only one member is blind, giving $1,377. - 2011-01-01: 1_377 - 2017-01-01: 1_504 - 2018-01-01: 1_534 - 2025-01-01: 1_975 - # 2026 value $3,031 as published on the Iowa HHS SSA standards page is a - # +53.5% jump vs 2025 ($1,975), out of step with the ~2.85% COLA applied to - # every other DP configuration. An expected ~$2,031 would match that COLA, + # 2011 Iowa HHS total $1,377 minus individual FBR $674 = state portion $703. + # (SSA 2011 Table 1 shows both-blind couple total $1,399; footnote a reduces + # the total by $22 when only one spouse is blind, giving $1,377.) + 2011-01-01: 703 + 2017-01-01: 769 + 2018-01-01: 784 + 2025-01-01: 1_008 + # 2026 Iowa HHS published total is $3,031; state portion = $3,031 − $994 FBR + # = $2,037. This is a +91.8% jump vs the 2025 state portion ($1,008), out of + # step with the ~2.85% COLA that every other DP configuration tracks. An + # expected state-portion of ~$1,037 (total ~$2,031) would match that COLA, # so $3,031 may reflect an Iowa HHS publication error. Encoded as published; - # pending confirmation from Iowa HHS. If Iowa HHS corrects the figure, - # update here. - 2026-01-01: 3_031 + # pending confirmation from Iowa HHS. + 2026-01-01: 2_037 BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT: - 2011-01-01: 1_399 - 2017-01-01: 1_526 - 2018-01-01: 1_556 - 2025-01-01: 1_997 - 2026-01-01: 2_053 + 2011-01-01: 725 + 2017-01-01: 791 + 2018-01-01: 806 + 2025-01-01: 1_030 + 2026-01-01: 1_059 NONE: 2011-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/state_supplement.yaml similarity index 72% rename from policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml rename to policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/state_supplement.yaml index 4a6c884eb1a..1388446f2ea 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/assistance_standard.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/state_supplement.yaml @@ -1,20 +1,20 @@ -description: Iowa provides this amount as the family-life home assistance standard under the State Supplementary Assistance program. +description: Iowa provides this state supplement amount above the federal SSI benefit rate (FBR) for family-life home residents under the State Supplementary Assistance program. values: - 2011-01-01: 816 - 2017-01-01: 897 - 2018-01-01: 912 - 2025-01-01: 1_129 - 2026-01-01: 1_156 + 2011-01-01: 142 + 2017-01-01: 162 + 2018-01-01: 162 + 2025-01-01: 162 + 2026-01-01: 162 metadata: unit: currency-USD period: month - label: Iowa SSA family-life home assistance standard + label: Iowa SSA family-life home state supplement reference: - title: Iowa Administrative Code 441—52.1(1) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 OS code D aged total + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 footnote a href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 - title: Iowa Administrative Code 441—52.1(1), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=119 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml index fec588ec726..27c6d99a0fe 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml @@ -242,9 +242,11 @@ # ============================================================================ # IAC 441—52.1(2): DP is federally-administered per POMS SI 01415.050.F. # Federally-administered SSP formula: -# supplement = max(0, payment_standard - max(countable, FBR)) -# capped at max_per_person_cap ($503 in 2025, $518 in 2026). -# Also requires dependent's countable income < dependent_income_limit. +# supplement = min(max(0, (FBR + state_supplement) - max(countable, FBR)), +# max_per_person_cap) +# max_per_person_cap = $503 in 2025, $518 in 2026. +# Also requires dependent's countable income < dependent_income_limit +# (enforced in ia_ssa_living_arrangement). - name: Case 1, person with no DP configuration gets zero supplement. period: 2025-01 @@ -490,10 +492,15 @@ # ============================================================================ # IAC 441—52.1(1): FLH is federally-administered per POMS SI 01415.050.F. # Federally-administered SSP formula: -# supplement = max(0, assistance_standard - max(countable, FBR)) -# capped at max_supplement ($142). +# base = min(max(0, (FBR + state_supplement) - max(countable, FBR)), +# max_supplement) +# extra = max(0, state_supplement - max_supplement) if countable == 0 +# supplement = base + extra +# $142 cap on the federally-administered portion; the Department pays the +# extra directly when SSA's $20 general-income disregard goes unused on an +# SSI-only recipient. -- name: Case 1, aged FLH resident with zero income (federal SSI plus capped state supplement). +- name: Case 1, aged FLH resident with zero income receives capped supplement plus Department top-up. period: 2025-01 absolute_error_margin: 0.01 input: @@ -516,13 +523,15 @@ members: [person1] state_code: IA output: - # Federal SSI fills to FBR $967; assistance standard $1,129; - # raw supplement = 1,129 - max(0, 967) = 162; capped at $142. + # Federal SSI fills to FBR $967; state supplement $162, capped at $142. + # With no other income the SSI $20 general-income disregard goes unused, + # so Iowa HHS pays the remaining $20 as a Department top-up, totaling + # $162 — bringing federal + state payments to the full $1,129 standard. is_ssi_eligible: [true] ssi: [967] ia_ssa_eligible: [true] ia_ssa_living_arrangement: [FLH] - ia_ssa: [142] + ia_ssa: [162] - name: Case 2, person not in FLH receives zero FLH supplement. period: 2025-01 @@ -575,7 +584,7 @@ ia_ssa_eligible: [false] ia_ssa: [0] -- name: Case 4, FLH resident 2026 still capped at 142 dollars. +- name: Case 4, FLH resident 2026 zero income receives 162 dollars (capped 142 plus 20 dollar top-up). period: 2026-01 absolute_error_margin: 0.01 input: @@ -598,8 +607,9 @@ members: [person1] state_code: IA output: - # Cap is frozen at $142 even though standard and PNA rise in 2026 - ia_ssa: [142] + # Cap frozen at $142; 2026 state supplement $162, so Department top-up + # of $20 applies to SSI-only recipient. Total Iowa payment $162. + ia_ssa: [162] - name: Case 5, FLH supplement phases down when countable income exceeds FBR. period: 2025-01 @@ -1007,6 +1017,45 @@ ia_ssa_ihhrc_both_need_care: [true, true] ia_ssa: [0, 0] +- name: Case 12, couple with only one recipient charges all participation to that recipient. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # $800/mo unearned per spouse; couple-combined ~$1,580 countable + # after the $20 disregard, exceeding the couple FBR $1,450 by $130. + social_security_retirement: 9_600 + ia_ssa_needs_in_home_health_related_care: true + ia_ssa_ihhrc_cost_of_care: 400 + person2: + age: 68 + social_security_retirement: 9_600 + ia_ssa_needs_in_home_health_related_care: false + ia_ssa_ihhrc_cost_of_care: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # person1 is the sole IHHRC recipient. Per IAC 441-177.10(2)(a) all of + # the household's remaining income after the FBR disregard is client + # participation for the one set of services, so person1 shoulders the + # full $130. Supplement = min($400, $480.55) − $130 = $270. person2 is + # not in the IHHRC category and receives $0. + ia_ssa_ihhrc_both_need_care: [false, false] + ia_ssa: [270, 0] + # ============================================================================ # RCF (Residential Care Facility) supplement tests (IAC 441—52.1(3)). # ============================================================================ diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index 8a7e37c3ae0..6b3b2963204 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -28,22 +28,36 @@ def formula(person, period, parameters): couple_fbr = parameters(period).gov.ssa.ssi.amount.couple joint_claim = person("ssi_claim_is_joint", period.this_year) basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) - # Federally-administered SSP V-shape: - # supplement = max(0, (FBR + state_standard) − max(countable, FBR)) - # Per POMS SI 01415.050.F, applied to Blind, DP, FLH. + # Federally-administered SSP V-shape (POMS SI 01415.050.F): + # supplement = max(0, (FBR + state_supplement) − max(countable, FBR)) + # applied to Blind, DP, FLH with their respective state-supplement + # parameters. countable_or_fbr = max_(countable_monthly, individual_fbr) - # BLIND — IAC 441—52.1(4): flat state standard ($22 frozen since 2011). + # BLIND — IAC 441—52.1(4): flat $22 state supplement (frozen since 2011). blind_amt = max_(0, (individual_fbr + p.blind) - countable_or_fbr) - # DP — IAC 441—52.1(2): configuration-keyed standard, capped per person. + # DP — IAC 441—52.1(2): state supplement varies by configuration, + # capped per person. dp_config = person("ia_ssa_dp_configuration", period) - dp_standard = p.dp.assistance_standard[dp_config] - dp_raw = max_(0, dp_standard - countable_or_fbr) + dp_state_supplement = p.dp.state_supplement[dp_config] + dp_raw = max_(0, (individual_fbr + dp_state_supplement) - countable_or_fbr) dp_amt = min_(dp_raw, p.dp.max_per_person_cap) - # FLH — IAC 441—52.1(1): the assistance_standard is the total - # standard (already includes the FBR portion), capped at - # max_supplement. - flh_raw = max_(0, p.flh.assistance_standard - countable_or_fbr) - flh_amt = min_(flh_raw, p.flh.max_supplement) + # FLH — IAC 441—52.1(1): state supplement capped at max_supplement + # ($142 frozen since 2011). For recipients whose only income is SSI + # (countable_monthly == 0), SSA's $20 general-income disregard goes + # unused, so Iowa HHS issues a separate Department payment equal to + # (state_supplement − max_supplement) to close the gap and bring total + # income to the full standard. In 2011 the state supplement equals + # max_supplement so no extra is owed; from 2017 onward the extra is $20. + flh_v_shape = max_( + 0, (individual_fbr + p.flh.state_supplement) - countable_or_fbr + ) + flh_base = min_(flh_v_shape, p.flh.max_supplement) + flh_extra = where( + countable_monthly == 0, + max_(0, p.flh.state_supplement - p.flh.max_supplement), + 0, + ) + flh_amt = flh_base + flh_extra # RCF — IAC 441—52.1(3): cost-of-care minus client participation. # Client participation = total monthly income (SSI countable + federal # SSI payment) minus the personal needs allowance. @@ -56,14 +70,21 @@ def formula(person, period, parameters): rcf_amt = max_(0, rcf_cost_of_care - rcf_client_participation) # IHHRC — IAC 441—177.10(2)(a) and 177.10(3): # payment = max(0, min(cost, per-person cap) − client participation). - # Client participation is combined marital-unit countable income - # after the basic SSI standard disregard (the applicable FBR for a - # single or joint claim), split evenly across marital-unit members. + # Client participation is combined marital-unit countable income after + # the basic SSI standard disregard (the applicable FBR for a single or + # joint claim). When both spouses need care, split evenly across the + # marital unit to avoid double-counting when the SPM unit aggregates; + # when only one spouse needs care, all combined participation is + # charged to the sole recipient because the services are provided to + # them alone. ihhrc_cost = person("ia_ssa_ihhrc_cost_of_care", period) + both_need_care = person("ia_ssa_ihhrc_both_need_care", period) combined_countable = person.marital_unit.sum(countable_monthly) combined_participation = max_(0, combined_countable - basic_ssi_disregard) - ihhrc_client_participation = ( - combined_participation / person.marital_unit.nb_persons() + ihhrc_client_participation = where( + both_need_care, + combined_participation / person.marital_unit.nb_persons(), + combined_participation, ) ihhrc_eligible_cost = min_(ihhrc_cost, p.ihhrc.max_cost_single) ihhrc_amt = max_(0, ihhrc_eligible_cost - ihhrc_client_participation) From 4f0bbd36a48fbcac618a4bf889b553409071c7b8 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 23 Apr 2026 01:01:37 -0400 Subject: [PATCH 14/23] Fix 2026 DP ceiling, DP 2018 cap and income limit, blind FLH increment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address three P2 review items: 1. 2026 DP BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: Iowa HHS's published $3,031 breaks the "-$22 when only one spouse is blind" footnote rule that's held for 2011/2017/2018/2025 and inflates the phase-down ceiling so high-income 2026 cases still receive DP when they should phase to zero. Encoded as the COLA-consistent total $2,031 (state portion $1,037). YAML comment documents the suspected Iowa HHS publication error and the basis for the override. 2. DP max_per_person_cap and dependent_income_limit now carry 2018-01-01: $387, matching the base state_supplement 2018 tier. Prior gap left 2018-2024 DP payments and eligibility understated against the 2017 $379 values. 3. FLH blind recipients receive the $22 blind increment on top of the federally-administered $142 cap (POMS OS code I: state portion $164 for blind FLH residents). The blind increment replaces — not adds to — the SSI-only Department top-up; $22 > $20 always. New FLH test case 7 locks in the $164 figure for a blind FLH resident. 79 Iowa SSA tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia/hhs/ssa/dp/dependent_income_limit.yaml | 3 ++ .../ia/hhs/ssa/dp/max_per_person_cap.yaml | 3 ++ .../ia/hhs/ssa/dp/state_supplement.yaml | 17 +++++----- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 31 +++++++++++++++++++ .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 28 +++++++++++------ 5 files changed, 66 insertions(+), 16 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml index a02f7021ff5..7de6b32364f 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml @@ -2,6 +2,7 @@ description: Iowa limits a dependent relative's countable income to this amount values: 2017-01-01: 379 + 2018-01-01: 387 2025-01-01: 503 2026-01-01: 518 @@ -14,6 +15,8 @@ metadata: href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 - title: Iowa Administrative Code 441—52.1(2) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) href: https://hhs.iowa.gov/media/15607/download - title: Iowa HHS State Supplementary Assistance Standards (current) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml index da45a2ee1e3..06e670e32f1 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml @@ -2,6 +2,7 @@ description: Iowa limits the dependent person supplement to this amount per elig values: 2017-01-01: 379 + 2018-01-01: 387 2025-01-01: 503 2026-01-01: 518 @@ -14,6 +15,8 @@ metadata: href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 - title: Iowa Administrative Code 441—52.1(2) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) href: https://hhs.iowa.gov/media/15607/download - title: Iowa HHS State Supplementary Assistance Standards (current) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml index 9e4137b9a41..df55cd817b3 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml @@ -46,13 +46,16 @@ BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: 2017-01-01: 769 2018-01-01: 784 2025-01-01: 1_008 - # 2026 Iowa HHS published total is $3,031; state portion = $3,031 − $994 FBR - # = $2,037. This is a +91.8% jump vs the 2025 state portion ($1,008), out of - # step with the ~2.85% COLA that every other DP configuration tracks. An - # expected state-portion of ~$1,037 (total ~$2,031) would match that COLA, - # so $3,031 may reflect an Iowa HHS publication error. Encoded as published; - # pending confirmation from Iowa HHS. - 2026-01-01: 2_037 + # Iowa HHS's 2026 page publishes this configuration at $3,031 total — a + # +53.5% jump vs 2025 ($1,975), out of step with the ~2.85% COLA applied to + # every other DP configuration and in conflict with the "-$22 when only one + # spouse is blind" footnote rule that holds for 2011/2017/2018/2025. The + # $3,031 value appears to be an Iowa HHS publication error (likely a + # transposed digit from an intended $2,031). Encoded as the COLA-consistent + # total $2,031 (state portion $1,037 = $2,031 − $994 FBR), which preserves + # the 14-year footnote pattern; revisit if Iowa HHS corrects the page or + # issues a General Letter confirming the higher figure. + 2026-01-01: 1_037 BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT: 2011-01-01: 725 2017-01-01: 791 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml index 27c6d99a0fe..49923cc336d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml @@ -665,6 +665,37 @@ # Countable $1,180/mo; standard $1,129; raw = max(0, 1129 - 1180) = 0. ia_ssa: [0] +- name: Case 7, blind FLH resident gets max_supplement plus 22 dollar blind increment. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + is_blind: true + employment_income: 0 + ia_ssa_resides_in_family_life_home: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # POMS OS code I (FLH blind): state portion = max_supplement $142 plus + # $22 blind increment = $164. The blind increment replaces the + # Department top-up ($22 > $20), so Department does not pay a top-up + # on top. + ia_ssa_living_arrangement: [FLH] + ia_ssa: [164] + # ============================================================================ # IHHRC (In-Home Health-Related Care) supplement tests (IAC 441—177). # ============================================================================ diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index 6b3b2963204..1acaf64dbcf 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -42,20 +42,30 @@ def formula(person, period, parameters): dp_raw = max_(0, (individual_fbr + dp_state_supplement) - countable_or_fbr) dp_amt = min_(dp_raw, p.dp.max_per_person_cap) # FLH — IAC 441—52.1(1): state supplement capped at max_supplement - # ($142 frozen since 2011). For recipients whose only income is SSI - # (countable_monthly == 0), SSA's $20 general-income disregard goes - # unused, so Iowa HHS issues a separate Department payment equal to - # (state_supplement − max_supplement) to close the gap and bring total - # income to the full standard. In 2011 the state supplement equals - # max_supplement so no extra is owed; from 2017 onward the extra is $20. + # ($142 frozen since 2011). Two add-ons on top of the capped base: + # - Blind recipients (POMS OS code I) receive the $22 blind + # increment on top of the federally-administered cap, giving a + # state portion of $164 in years with a $142 cap. + # - Non-blind recipients with SSI-only income (countable_monthly + # == 0) receive a separate Department top-up equal to + # (state_supplement − max_supplement) so total income reaches + # the full standard; SSA's $20 general-income disregard goes + # unused in that case. + # The two add-ons are alternatives (blind increment replaces the + # Department top-up), not additive. flh_v_shape = max_( 0, (individual_fbr + p.flh.state_supplement) - countable_or_fbr ) flh_base = min_(flh_v_shape, p.flh.max_supplement) + is_blind = person("is_blind", period.this_year) flh_extra = where( - countable_monthly == 0, - max_(0, p.flh.state_supplement - p.flh.max_supplement), - 0, + is_blind, + p.blind, + where( + countable_monthly == 0, + max_(0, p.flh.state_supplement - p.flh.max_supplement), + 0, + ), ) flh_amt = flh_base + flh_extra # RCF — IAC 441—52.1(3): cost-of-care minus client participation. From ef807e00bbe3dc3e767cf55df0b84cb172483aed Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 4 May 2026 15:01:55 -0400 Subject: [PATCH 15/23] Apply Pavel's review fixes: DP couple-FBR, $20 disregard, resource limit, IAC citations, SMME FPG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DP: replace state_supplement (back-calculated against individual FBR) with per-config assistance_standard from GL 6-B-46 p. 22; pick couple FBR for spouse-inclusive configs. Removes the unjustified $503 max_per_person_cap that was conflated with the dependent_income_limit. Fixes 2025 BLIND configs that were understated by $22-$44/mo. - RCF/IHHRC: add ia_ssa_countable_income_no_disregard helper to reverse the SSI \$20 general exclusion (GL 6-B-46 pp. 36, 54-58 omit it). Accounts for SSI couple computation by sharing the add-back across the marital unit. FLH/DP/Blind keep ssi_countable_income — they are SSA-administered and the \$20 disregard is real money the recipient receives. - Resource limit: dispatch on marital_unit.nb_persons() > 1 instead of ssi_claim_is_joint, so an aged recipient with an ineligible-but-co-resident spouse correctly gets the IAC 441-51.5(2) couple \$3,000 limit. - IAC citations: 51.6(6) -> 51.7(6) for SMME 2026 ref, 51.4(1) -> 51.5(1) for DP dependent income limit, 51.3(3) -> 51.4(3) for RCF days_multiplier and the matching comment. - SMME income test: size FPG by 1-person (or 2-person on joint claim) per IAC 441-51.7(6) "income of a recipient", not by full SPM unit. - Tests: refresh DP/RCF/IHHRC expected values for the new formulas; add a resources test for ineligible-co-resident-spouse; restructure DP cases 3, 4, 8 with realistic 3-person setups instead of single person tagged with couple-inclusive configurations. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia/hhs/ssa/dp/assistance_standard.yaml | 64 ++++++++ .../ia/hhs/ssa/dp/dependent_income_limit.yaml | 2 +- .../ia/hhs/ssa/dp/max_per_person_cap.yaml | 23 --- .../ia/hhs/ssa/dp/state_supplement.yaml | 66 -------- .../ia/hhs/ssa/rcf/days_multiplier.yaml | 4 +- .../smme/minimum_income_fpl_multiplier.yaml | 2 +- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 148 +++++++++++------- .../ia/hhs/ssa/ia_ssa_living_arrangement.yaml | 2 +- .../ia/hhs/ssa/ia_ssa_resources_eligible.yaml | 28 ++++ .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 100 +++++++----- .../ia_ssa_countable_income_no_disregard.py | 43 +++++ .../ia/hhs/ssa/ia_ssa_living_arrangement.py | 45 +++--- .../ia/hhs/ssa/ia_ssa_resources_eligible.py | 25 +-- .../ia/hhs/ssa/smme/ia_ssa_smme_eligible.py | 17 +- 14 files changed, 337 insertions(+), 232 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml delete mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml delete mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml new file mode 100644 index 00000000000..ec397918787 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/assistance_standard.yaml @@ -0,0 +1,64 @@ +description: Iowa provides this monthly assistance standard for dependent person configurations under the State Supplementary Assistance program. + +metadata: + unit: currency-USD + period: month + label: Iowa SSA dependent person assistance standard + breakdown: + - ia_ssa_dp_configuration + reference: + - title: Iowa Administrative Code 441—52.1(2) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 + - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 OS code C totals + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 + - title: Iowa Administrative Code 441—52.1(2), January 4, 2017 supplement + href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=119 + - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update + href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 + - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) + href: https://hhs.iowa.gov/media/15607/download + - title: Iowa HHS State Supplementary Assistance Standards (current) + href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance + +AGED_OR_DISABLED_WITH_DEPENDENT: + 2011-01-01: 1_018 + 2017-01-01: 1_114 + 2018-01-01: 1_137 + 2025-01-01: 1_470 + 2026-01-01: 1_512 +AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT: + 2011-01-01: 1_355 + 2017-01-01: 1_482 + 2018-01-01: 1_512 + 2025-01-01: 1_953 + 2026-01-01: 2_009 +BLIND_WITH_DEPENDENT: + 2011-01-01: 1_040 + 2017-01-01: 1_136 + 2018-01-01: 1_159 + 2025-01-01: 1_492 + 2026-01-01: 1_534 +BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: + # 2011 Iowa HHS total; SSA 2011 Table 1 shows both-blind couple total $1,399; + # footnote a reduces the total by $22 when only one spouse is blind, giving $1,377. + 2011-01-01: 1_377 + 2017-01-01: 1_504 + 2018-01-01: 1_534 + 2025-01-01: 1_975 + # Iowa HHS's 2026 page publishes this configuration at $3,031 — a +53.5% jump + # vs 2025 ($1,975), out of step with the ~2.85% COLA applied to every other + # DP configuration and in conflict with the "-$22 when only one spouse is blind" + # footnote rule that holds for 2011/2017/2018/2025. The $3,031 value appears + # to be an Iowa HHS publication error (likely a transposed digit from an + # intended $2,031). Encoded as the COLA-consistent total $2,031, which + # preserves the 14-year footnote pattern; revisit if Iowa HHS corrects the + # page or issues a General Letter confirming the higher figure. + 2026-01-01: 2_031 +BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT: + 2011-01-01: 1_399 + 2017-01-01: 1_526 + 2018-01-01: 1_556 + 2025-01-01: 1_997 + 2026-01-01: 2_053 +NONE: + 2011-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml index 7de6b32364f..b7d2aedb5fb 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml @@ -11,7 +11,7 @@ metadata: period: month label: Iowa SSA dependent person dependent income limit reference: - - title: Iowa Administrative Code 441—51.4(1), January 4, 2017 supplement + - title: Iowa Administrative Code 441—51.5(1), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 - title: Iowa Administrative Code 441—52.1(2) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml deleted file mode 100644 index 06e670e32f1..00000000000 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/max_per_person_cap.yaml +++ /dev/null @@ -1,23 +0,0 @@ -description: Iowa limits the dependent person supplement to this amount per eligible person under the State Supplementary Assistance program. - -values: - 2017-01-01: 379 - 2018-01-01: 387 - 2025-01-01: 503 - 2026-01-01: 518 - -metadata: - unit: currency-USD - period: month - label: Iowa SSA dependent person maximum payment per person - reference: - - title: Iowa Administrative Code 441—51.4(1), January 4, 2017 supplement - href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 - - title: Iowa Administrative Code 441—52.1(2) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update - href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 - - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) - href: https://hhs.iowa.gov/media/15607/download - - title: Iowa HHS State Supplementary Assistance Standards (current) - href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml deleted file mode 100644 index df55cd817b3..00000000000 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/state_supplement.yaml +++ /dev/null @@ -1,66 +0,0 @@ -description: Iowa provides this state supplement amount above the federal SSI benefit rate (FBR) for dependent person configurations under the State Supplementary Assistance program. - -metadata: - unit: currency-USD - period: month - label: Iowa SSA dependent person state supplement - breakdown: - - ia_ssa_dp_configuration - reference: - - title: Iowa Administrative Code 441—52.1(2) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 OS code C totals - href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 - - title: Iowa Administrative Code 441—52.1(2), January 4, 2017 supplement - href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=119 - - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update - href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 - - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) - href: https://hhs.iowa.gov/media/15607/download - - title: Iowa HHS State Supplementary Assistance Standards (current) - href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance - -AGED_OR_DISABLED_WITH_DEPENDENT: - 2011-01-01: 344 - 2017-01-01: 379 - 2018-01-01: 387 - 2025-01-01: 503 - 2026-01-01: 518 -AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT: - 2011-01-01: 681 - 2017-01-01: 747 - 2018-01-01: 762 - 2025-01-01: 986 - 2026-01-01: 1_015 -BLIND_WITH_DEPENDENT: - 2011-01-01: 366 - 2017-01-01: 401 - 2018-01-01: 409 - 2025-01-01: 525 - 2026-01-01: 540 -BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: - # 2011 Iowa HHS total $1,377 minus individual FBR $674 = state portion $703. - # (SSA 2011 Table 1 shows both-blind couple total $1,399; footnote a reduces - # the total by $22 when only one spouse is blind, giving $1,377.) - 2011-01-01: 703 - 2017-01-01: 769 - 2018-01-01: 784 - 2025-01-01: 1_008 - # Iowa HHS's 2026 page publishes this configuration at $3,031 total — a - # +53.5% jump vs 2025 ($1,975), out of step with the ~2.85% COLA applied to - # every other DP configuration and in conflict with the "-$22 when only one - # spouse is blind" footnote rule that holds for 2011/2017/2018/2025. The - # $3,031 value appears to be an Iowa HHS publication error (likely a - # transposed digit from an intended $2,031). Encoded as the COLA-consistent - # total $2,031 (state portion $1,037 = $2,031 − $994 FBR), which preserves - # the 14-year footnote pattern; revisit if Iowa HHS corrects the page or - # issues a General Letter confirming the higher figure. - 2026-01-01: 1_037 -BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT: - 2011-01-01: 725 - 2017-01-01: 791 - 2018-01-01: 806 - 2025-01-01: 1_030 - 2026-01-01: 1_059 -NONE: - 2011-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml index 41e111098cb..f3b9a90d63c 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml @@ -8,9 +8,9 @@ metadata: period: eternity label: Iowa SSA residential care facility days-per-month multiplier reference: - - title: Iowa Administrative Code 441—51.3(3) + - title: Iowa Administrative Code 441—51.4(3) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 - title: Iowa Administrative Code 441—52.1(3) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 - - title: Iowa Administrative Code 441—51.3(3), January 4, 2017 supplement + - title: Iowa Administrative Code 441—51.4(3), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml index 004f643af7f..f5ced35272d 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml @@ -8,7 +8,7 @@ metadata: period: year label: Iowa SSA SMME minimum income FPL multiplier reference: - - title: Iowa Administrative Code 441—51.6(6) + - title: Iowa Administrative Code 441—51.7(6) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 - title: Iowa Administrative Code 441—51.6(6), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=114 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml index 49923cc336d..f46e48374b8 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml @@ -241,10 +241,12 @@ # DP (Dependent Person) supplement tests (IAC 441—52.1(2): 5 configurations). # ============================================================================ # IAC 441—52.1(2): DP is federally-administered per POMS SI 01415.050.F. -# Federally-administered SSP formula: -# supplement = min(max(0, (FBR + state_supplement) - max(countable, FBR)), -# max_per_person_cap) -# max_per_person_cap = $503 in 2025, $518 in 2026. +# Iowa GL 6-B-46 p. 22 publishes a per-configuration assistance standard. +# Per the manual ("Only the income of the eligible person or eligible couple +# is subtracted from the applicable assistance standard"), the supplement is: +# supplement = max(0, assistance_standard - max(countable, applicable_FBR)) +# where applicable_FBR is the couple FBR for configurations that include an +# eligible spouse, and the individual FBR otherwise. # Also requires dependent's countable income < dependent_income_limit # (enforced in ia_ssa_living_arrangement). @@ -300,60 +302,87 @@ ia_ssa_eligible: [false] ia_ssa: [0] -- name: Case 3, DP supplement capped at per-person maximum 503 dollars. +- name: Case 3, blind client with aged spouse and dependent child receives DP at couple-FBR-based standard. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 + is_blind: true employment_income: 0 - ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_configuration: BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT ia_ssa_dp_has_eligible_dependent: true ia_ssa_dp_dependent_countable_income: 0 + person2: + age: 68 + is_blind: false + employment_income: 0 + ia_ssa_dp_configuration: NONE + person3: + age: 10 + employment_income: 0 marital_units: - marital_unit: - members: [person1] + first_marital_unit: + members: [person1, person2] + second_marital_unit: + members: [person3] tax_units: tax_unit: - members: [person1] + members: [person1, person2, person3] spm_units: spm_unit: - members: [person1] + members: [person1, person2, person3] households: household: - members: [person1] + members: [person1, person2, person3] state_code: IA output: - # Standard $1,997 minus federal SSI and income; well above $503 cap - ia_ssa: [503] + # person1: DP standard $1,975 minus couple FBR $1,450 = $525. + # person2: aged spouse with no DP/BLIND/SMME qualification -> NONE. + # person3: child -> NONE. + ia_ssa_living_arrangement: [DP, NONE, NONE] + ia_ssa: [525, 0, 0] -- name: Case 4, DP supplement cap rises to 518 dollars in 2026. +- name: Case 4, blind client with aged spouse and dependent child at 2026 rates. period: 2026-01 absolute_error_margin: 0.01 input: people: person1: age: 70 + is_blind: true employment_income: 0 - ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_configuration: BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT ia_ssa_dp_has_eligible_dependent: true ia_ssa_dp_dependent_countable_income: 0 + person2: + age: 68 + is_blind: false + employment_income: 0 + ia_ssa_dp_configuration: NONE + person3: + age: 10 + employment_income: 0 marital_units: - marital_unit: - members: [person1] + first_marital_unit: + members: [person1, person2] + second_marital_unit: + members: [person3] tax_units: tax_unit: - members: [person1] + members: [person1, person2, person3] spm_units: spm_unit: - members: [person1] + members: [person1, person2, person3] households: household: - members: [person1] + members: [person1, person2, person3] state_code: IA output: - ia_ssa: [518] + # 2026 DP standard $2,031 minus 2026 couple FBR $1,491 = $540. + ia_ssa_living_arrangement: [DP, NONE, NONE] + ia_ssa: [540, 0, 0] - name: Case 5, aged client with aged spouse and dependent child integration. period: 2025-01 @@ -389,10 +418,11 @@ members: [person1, person2, person3] state_code: IA output: - # person1: DP capped at $503. - # person2: income above 120% FPL for household of 3 would be required - # for SMME ($26,650 × 1.2 / 12 = $2,665/mo); but income is $0, so not - # SMME-eligible -> NONE. + # person1: aged + aged-spouse + dependent. Standard $1,953, couple FBR + # $1,450: max(0, 1953 - max(0, 1450)) = $503. + # person2: aged with no DP configuration; for SMME income must exceed + # 120% FPL for one person ($1,565/mo with the new 1-person/2-person + # FPG sizing); income is $0, so not SMME-eligible -> NONE. # person3: child -> NONE. ia_ssa_living_arrangement: [DP, NONE, NONE] ia_ssa: [503, 0, 0] @@ -451,21 +481,21 @@ members: [person1] state_code: IA output: - # 2017 AGED_OR_DISABLED_WITH_DEPENDENT payment standard $1,114; FBR $735; - # max_per_person_cap $379. Federally-administered formula: - # max(0, 1114 - max(0, 735)) = $379 -> capped at $379. + # 2017 AGED_OR_DISABLED_WITH_DEPENDENT standard $1,114; individual FBR $735. + # Single eligible person -> applicable FBR is individual. + # max(0, 1114 - max(0, 735)) = $379. ia_ssa_living_arrangement: [DP] ia_ssa: [379] -- name: Case 8, DP supplement phases down when countable income exceeds FBR. +- name: Case 8, DP supplement phases down when single client's countable income exceeds FBR. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - social_security_retirement: 20_640 # $1,720/mo - ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + social_security_retirement: 15_600 # $1,300/mo + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT ia_ssa_dp_has_eligible_dependent: true ia_ssa_dp_dependent_countable_income: 0 marital_units: @@ -482,10 +512,11 @@ members: [person1] state_code: IA output: - # $1,720/mo SS gross -> $1,700/mo countable. Payment standard $1,997, - # FBR $967. Federally-administered formula: - # max(0, 1997 - max(1700, 967)) = $297 (under the $503 cap). - ia_ssa: [297] + # $1,300/mo SS gross -> $1,280/mo countable (after SSI $20 disregard, + # which DP retains because DP is federally administered). Standard + # $1,470, individual FBR $967 (single eligible client): + # max(0, 1470 - max(1280, 967)) = $190. + ia_ssa: [190] # ============================================================================ # FLH (Family-Life Home) supplement tests (IAC 441—52.1(1)). @@ -944,8 +975,9 @@ members: [person1] state_code: IA output: - # Countable $1,647/mo minus individual FBR disregard $967 = $680, which - # exceeds the single cap $480.55 -> not in IHHRC category -> no supplement. + # Countable for IHHRC (no SSI $20 disregard) $1,667/mo minus individual + # FBR disregard $967 = $700, which exceeds the single cap $480.55 -> not + # in IHHRC category -> no supplement. ia_ssa: [0] - name: Case 9, single person with countable income below FBR gets full supplement. @@ -972,9 +1004,9 @@ members: [person1] state_code: IA output: - # $800/mo SS gross, countable $780/mo. Individual FBR disregard $967 makes - # income after disregard 0 -> passes single cap. Client participation is - # 0 -> supplement equals cost $400. + # $800/mo SS unearned. IHHRC countable (no $20 disregard) $800/mo. + # Individual FBR disregard $967 makes income after disregard 0 -> passes + # single cap. Client participation is 0 -> supplement equals cost $400. ia_ssa: [400] - name: Case 10, couple both needing IHHRC with combined countable below couple FBR. @@ -1006,10 +1038,10 @@ members: [person1, person2] state_code: IA output: - # Each spouse's countable unearned is about $580/mo after the $20 general - # disregard, combined ~$1,160. Couple FBR disregard $1,450 leaves 0 after - # disregard -> passes couple cap $961.10. Client participation is 0 -> - # each person's supplement equals cost $400. + # Each spouse's IHHRC countable (no $20 disregard) is $600/mo, combined + # $1,200. Couple FBR disregard $1,450 leaves 0 after disregard -> passes + # couple cap $961.10. Client participation is 0 -> each person's + # supplement equals cost $400. ia_ssa_ihhrc_both_need_care: [true, true] ia_ssa: [400, 400] @@ -1042,9 +1074,9 @@ members: [person1, person2] state_code: IA output: - # Each spouse's countable ~$1,300/mo; combined ~$2,600. After couple FBR - # disregard $1,450 -> $1,150 countable, which exceeds the couple cap - # $961.10 -> both ineligible. + # Each spouse's IHHRC countable (no $20 disregard) is $1,320/mo; combined + # $2,640. After couple FBR disregard $1,450 -> $1,190 countable, which + # exceeds the couple cap $961.10 -> both ineligible. ia_ssa_ihhrc_both_need_care: [true, true] ia_ssa: [0, 0] @@ -1079,13 +1111,13 @@ members: [person1, person2] state_code: IA output: - # person1 is the sole IHHRC recipient. Per IAC 441-177.10(2)(a) all of - # the household's remaining income after the FBR disregard is client - # participation for the one set of services, so person1 shoulders the - # full $130. Supplement = min($400, $480.55) − $130 = $270. person2 is - # not in the IHHRC category and receives $0. + # person1 is the sole IHHRC recipient. Each spouse has $800/mo IHHRC + # countable (no $20 disregard); combined $1,600 minus couple FBR $1,450 + # = $150. Per IAC 441-177.10(2)(a) all of that participation is charged + # to the one recipient. Supplement = min($400, $480.55) − $150 = $250. + # person2 is not in the IHHRC category and receives $0. ia_ssa_ihhrc_both_need_care: [false, false] - ia_ssa: [270, 0] + ia_ssa: [250, 0] # ============================================================================ # RCF (Residential Care Facility) supplement tests (IAC 441—52.1(3)). @@ -1260,10 +1292,12 @@ members: [person1] state_code: IA output: - # $1,000/mo SS, countable $980; no SSI (countable > FBR minus $0 state - # standard); total monthly income $980; client participation - # $980 - $126 = $854; supplement = $1,165.60 - $854 = $311.60. - ia_ssa: [311.60] + # $1,000/mo SS unearned. RCF does not allow the SSI $20 disregard + # (GL 6-B-46 p. 54), so countable for RCF is $1,000 (not $980). No SSI + # (SSI's calc treats countable as $980 > FBR $967 -> $0). Total monthly + # income $1,000; client participation $1,000 - $126 = $874; supplement + # = $1,165.60 - $874 = $291.60. + ia_ssa: [291.60] - name: Case 7, RCF resident with income above 31 times max per diem is ineligible. period: 2025-01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml index 56bf8910c0c..6573f32780d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml @@ -1,7 +1,7 @@ # Verifies ia_ssa_living_arrangement priority ordering: # RCF > IHHRC > FLH > DP > BLIND > SMME > NONE # -# Note: SMME requires income > 120% FPL (IAC 441—51.6(6)). 2025 FPL 1-person +# Note: SMME requires income > 120% FPL (IAC 441—51.7(6)). 2025 FPL 1-person # (contiguous US) = $15,650; 120% = $18,780/year or $1,565/month. - name: Case 1, RCF resident who is also blind gets RCF category not BLIND. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml index 7b268ed42bf..9f519b4b85d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.yaml @@ -90,3 +90,31 @@ # Combined $4,000 exceeds the couple limit $3,000 -> both ineligible, even # though each individual is below the single limit. ia_ssa_resources_eligible: [false, false] + +- name: Case 6, aged recipient with non-disabled co-resident spouse uses couple limit. + period: 2025-01 + input: + people: + person1: + age: 70 + is_disabled: false + ssi_countable_resources: 1_500 + person2: + age: 50 + is_disabled: false + ssi_countable_resources: 1_500 + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Spouse is not categorically SSI-eligible (under 65, not disabled), so + # ssi_claim_is_joint is false. Per IAC 441—51.5(2) Iowa still applies the + # $3,000 couple limit when there is a dependent spouse (51.5(4) covers + # ineligible-but-financially-dependent spouses). Combined $3,000 -> both + # eligible. Without this fix the recipient would be tested individually + # at $2,000 and lose eligibility despite Iowa's rule. + ia_ssa_resources_eligible: [true, true] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index 1acaf64dbcf..7f69070272a 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -11,6 +11,7 @@ class ia_ssa(Variable): reference = ( "https://www.legis.iowa.gov/docs/code/249.3.pdf", "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf", + "https://hhs.iowa.gov/media/15607/download", "https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance", ) @@ -18,43 +19,55 @@ def formula(person, period, parameters): arrangement = person("ia_ssa_living_arrangement", period) arr_values = arrangement.possible_values p = parameters(period).gov.states.ia.hhs.ssa - # Monthly income helpers. countable_monthly = ( person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR ) ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR - total_rcf_income = countable_monthly + ssi_monthly - individual_fbr = parameters(period).gov.ssa.ssi.amount.individual - couple_fbr = parameters(period).gov.ssa.ssi.amount.couple - joint_claim = person("ssi_claim_is_joint", period.this_year) - basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) - # Federally-administered SSP V-shape (POMS SI 01415.050.F): - # supplement = max(0, (FBR + state_supplement) − max(countable, FBR)) - # applied to Blind, DP, FLH with their respective state-supplement - # parameters. - countable_or_fbr = max_(countable_monthly, individual_fbr) + # Iowa RCF, FLH-eligibility, and IHHRC do not allow the SSI $20 general + # income disregard (GL 6-B-46 pp. 30, 36–38, 54–58). RCF and IHHRC are + # state-administered, so this helper restores the $20 the SSI exclusion + # already removed. + countable_no_disregard = person("ia_ssa_countable_income_no_disregard", period) + p_ssi = parameters(period).gov.ssa.ssi.amount + individual_fbr = p_ssi.individual + couple_fbr = p_ssi.couple # BLIND — IAC 441—52.1(4): flat $22 state supplement (frozen since 2011). - blind_amt = max_(0, (individual_fbr + p.blind) - countable_or_fbr) - # DP — IAC 441—52.1(2): state supplement varies by configuration, - # capped per person. + # Federally administered, so SSA's $20 disregard applies via + # ssi_countable_income. + blind_amt = max_( + 0, (individual_fbr + p.blind) - max_(countable_monthly, individual_fbr) + ) + # DP — IAC 441—52.1(2): per-configuration assistance standard. Pick the + # applicable Federal Benefit Rate (couple FBR for configurations that + # include an eligible spouse, individual FBR otherwise) so the + # supplement equals (standard − max(countable, applicable_fbr)). dp_config = person("ia_ssa_dp_configuration", period) - dp_state_supplement = p.dp.state_supplement[dp_config] - dp_raw = max_(0, (individual_fbr + dp_state_supplement) - countable_or_fbr) - dp_amt = min_(dp_raw, p.dp.max_per_person_cap) - # FLH — IAC 441—52.1(1): state supplement capped at max_supplement - # ($142 frozen since 2011). Two add-ons on top of the capped base: - # - Blind recipients (POMS OS code I) receive the $22 blind - # increment on top of the federally-administered cap, giving a - # state portion of $164 in years with a $142 cap. - # - Non-blind recipients with SSI-only income (countable_monthly - # == 0) receive a separate Department top-up equal to - # (state_supplement − max_supplement) so total income reaches - # the full standard; SSA's $20 general-income disregard goes - # unused in that case. - # The two add-ons are alternatives (blind increment replaces the - # Department top-up), not additive. + dp_config_values = dp_config.possible_values + dp_assistance_standard = p.dp.assistance_standard[dp_config] + dp_has_spouse = ( + (dp_config == dp_config_values.AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT) + | ( + dp_config + == dp_config_values.BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT + ) + | (dp_config == dp_config_values.BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT) + ) + dp_applicable_fbr = where(dp_has_spouse, couple_fbr, individual_fbr) + dp_amt = max_( + 0, + dp_assistance_standard - max_(countable_monthly, dp_applicable_fbr), + ) + # FLH — IAC 441—52.1(1): SSA-administered, so the V-shape uses + # ssi_countable_income (with the $20 disregard SSA actually applies). + # The $142 SSA cap caps the federally-administered piece; for SSI-only + # recipients (no unearned income to absorb the $20 disregard), the + # Department pays the (state_supplement − cap) gap so total income + # reaches the standard. The blind increment ($22) replaces this gap + # payment for blind recipients. flh_v_shape = max_( - 0, (individual_fbr + p.flh.state_supplement) - countable_or_fbr + 0, + (individual_fbr + p.flh.state_supplement) + - max_(countable_monthly, individual_fbr), ) flh_base = min_(flh_v_shape, p.flh.max_supplement) is_blind = person("is_blind", period.this_year) @@ -69,27 +82,32 @@ def formula(person, period, parameters): ) flh_amt = flh_base + flh_extra # RCF — IAC 441—52.1(3): cost-of-care minus client participation. - # Client participation = total monthly income (SSI countable + federal - # SSI payment) minus the personal needs allowance. + # Client participation = total monthly income (countable + SSI) minus + # the personal needs allowance. Iowa GL 6-B-46 p. 54 omits the SSI $20 + # disregard, so use countable_no_disregard. Other regulatory deductions + # (impairment-related work expenses, dependent diversions, unmet + # medical needs, first-month expenses) are not modeled. rcf_per_diem = person("ia_ssa_rcf_cost_per_diem", period) rcf_capped_per_diem = min_(rcf_per_diem, p.rcf.max_per_diem) rcf_cost_of_care = rcf_capped_per_diem * p.rcf.days_multiplier + rcf_total_income = countable_no_disregard + ssi_monthly rcf_client_participation = max_( - 0, total_rcf_income - p.rcf.personal_needs_allowance + 0, rcf_total_income - p.rcf.personal_needs_allowance ) rcf_amt = max_(0, rcf_cost_of_care - rcf_client_participation) # IHHRC — IAC 441—177.10(2)(a) and 177.10(3): # payment = max(0, min(cost, per-person cap) − client participation). - # Client participation is combined marital-unit countable income after - # the basic SSI standard disregard (the applicable FBR for a single or - # joint claim). When both spouses need care, split evenly across the - # marital unit to avoid double-counting when the SPM unit aggregates; - # when only one spouse needs care, all combined participation is - # charged to the sole recipient because the services are provided to - # them alone. + # Client participation = combined marital-unit countable income + # (without the SSI $20 disregard, per GL 6-B-46 p. 36) minus the + # applicable FBR. When both spouses need care, split evenly across the + # marital unit so SPM-unit aggregation does not double-count. + # Home-maintenance, dependent-diversion, and medical-need deductions + # are not modeled. ihhrc_cost = person("ia_ssa_ihhrc_cost_of_care", period) both_need_care = person("ia_ssa_ihhrc_both_need_care", period) - combined_countable = person.marital_unit.sum(countable_monthly) + joint_claim = person("ssi_claim_is_joint", period.this_year) + basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) + combined_countable = person.marital_unit.sum(countable_no_disregard) combined_participation = max_(0, combined_countable - basic_ssi_disregard) ihhrc_client_participation = where( both_need_care, diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py new file mode 100644 index 00000000000..617d331a16e --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py @@ -0,0 +1,43 @@ +from policyengine_us.model_api import * + + +class ia_ssa_countable_income_no_disregard(Variable): + value_type = float + entity = Person + definition_period = MONTH + label = "Iowa SSA monthly countable income, without the SSI $20 general income disregard" + unit = USD + defined_for = StateCode.IA + reference = ( + "https://hhs.iowa.gov/media/15607/download", + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2", + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2", + ) + + def formula(person, period, parameters): + # GL 6-B-46 pp. 30, 36–38, 54–58: Iowa RCF, FLH-eligibility, and IHHRC + # do not allow the SSI $20 general income disregard. ssi_countable_income + # already applies that exclusion (in _apply_ssi_exclusions), so add back + # the amount that was actually applied. + # + # When both spouses are SSI-eligible (couple computation applies), SSI + # applies the $20 once to combined unearned and then splits the result + # evenly across the two spouses; the per-person add-back is then half + # of min(combined_unearned, $20). Otherwise the $20 applies to this + # person's own unearned income. + p = parameters(period).gov.ssa.ssi.income.exclusions + countable_monthly = ( + person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + own_unearned_monthly = ( + person("ssi_unearned_income", period.this_year) / MONTHS_IN_YEAR + ) + couple = person("ssi_couple_computation_applies", period.this_year) + combined_unearned_monthly = person.marital_unit.sum(own_unearned_monthly) + addback = where( + couple, + min_(combined_unearned_monthly, p.general) + / person.marital_unit.nb_persons(), + min_(own_unearned_monthly, p.general), + ) + return countable_monthly + addback diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py index ae4a679a1ce..af700f8a8a5 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py @@ -24,26 +24,23 @@ class ia_ssa_living_arrangement(Variable): def formula(person, period, parameters): eligible = person("ia_ssa_eligible", period) p = parameters(period).gov.states.ia.hhs.ssa - # Monthly SSI countable income and federal SSI payment; both source - # variables are annual, so divide by 12 for use in monthly formulas. countable_monthly = ( person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR ) ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR - total_rcf_income = countable_monthly + ssi_monthly - # Federal SSI parameters used below for the FBR-based disregard. - individual_fbr = parameters(period).gov.ssa.ssi.amount.individual - couple_fbr = parameters(period).gov.ssa.ssi.amount.couple + countable_no_disregard = person("ia_ssa_countable_income_no_disregard", period) + p_ssi = parameters(period).gov.ssa.ssi.amount + individual_fbr = p_ssi.individual + couple_fbr = p_ssi.couple joint_claim = person("ssi_claim_is_joint", period.this_year) basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) - # IAC 441—51.3(3) cross-refs 52.1(3)"a": RCF income eligibility - # compares client participation (total monthly income minus the - # personal needs allowance) against 31 × the maximum per diem. The - # 2025 Iowa HHS manual states the rule as: a person meets income - # eligibility when client participation is less than the cost of care - # for a 31-day month. + # IAC 441—51.4(3) cross-refs 52.1(3)"a": RCF income eligibility compares + # client participation (total monthly income minus the personal needs + # allowance) against 31 × the maximum per diem. GL 6-B-46 p. 54 omits + # the SSI $20 disregard, so use countable_no_disregard. + rcf_total_income = countable_no_disregard + ssi_monthly rcf_client_participation = max_( - 0, total_rcf_income - p.rcf.personal_needs_allowance + 0, rcf_total_income - p.rcf.personal_needs_allowance ) in_rcf = person("ia_ssa_resides_in_residential_care_facility", period) rcf_income_threshold = p.rcf.days_multiplier * p.rcf.max_per_diem @@ -52,11 +49,9 @@ def formula(person, period, parameters): both_need_care = person("ia_ssa_ihhrc_both_need_care", period) # IAC 441—177.4(1)(f) caps combined marital-unit countable income at # $480.55 (one spouse needs care) or $961.10 (both need care) after - # the basic SSI standard disregard (the applicable FBR for a single - # or joint claim). Compare combined marital-unit income against the - # applicable cap for both configurations so the rule is enforced - # symmetrically. - combined_countable = person.marital_unit.sum(countable_monthly) + # the basic SSI standard disregard. GL 6-B-46 p. 36 omits the $20 + # disregard, so use countable_no_disregard. + combined_countable = person.marital_unit.sum(countable_no_disregard) ihhrc_countable_after_disregard = max_( 0, combined_countable - basic_ssi_disregard ) @@ -71,17 +66,17 @@ def formula(person, period, parameters): has_dependent = person("ia_ssa_dp_has_eligible_dependent", period) dp_configuration = person("ia_ssa_dp_configuration", period) in_dp = dp_configuration != dp_configuration.possible_values.NONE - # IAC 441—52.1(2): DP requires the dependent's countable income to be - # below the dependent income limit. Gate DP at the living-arrangement - # level so people who qualify for DP but fail the dependent-income - # test fall through to Blind / SMME rather than receiving a zero DP - # supplement. + # IAC 441—52.1(2): DP requires the dependent's countable income below + # the dependent income limit (per IAC 441—51.5(1)). Gate at the + # living-arrangement level so people who qualify for DP but fail the + # dependent-income test fall through to Blind / SMME rather than + # receiving a zero DP supplement. dependent_income = person("ia_ssa_dp_dependent_countable_income", period) dependent_income_eligible = dependent_income < p.dp.dependent_income_limit is_blind = person("is_blind", period.this_year) # IAC 441—52.1(4) blind standard is a federally-administered SSP; - # supplement phases to zero when countable income reaches FBR + - # state standard. Mirror that ceiling in the category gate so blind + # supplement phases to zero when countable income reaches FBR + state + # standard. Mirror that ceiling in the category gate so blind # recipients with excess income fall through to the next category. blind_income_eligible = countable_monthly < individual_fbr + p.blind smme_eligible = person("ia_ssa_smme_eligible", period) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py index 9dc337a42e4..339b2aae4e8 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py @@ -7,18 +7,23 @@ class ia_ssa_resources_eligible(Variable): definition_period = MONTH label = "Iowa SSA resources eligible" defined_for = StateCode.IA - reference = "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf" + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" + ) def formula(person, period, parameters): + # IAC 441—51.5(2): the recipient resource limit is $2,000 alone or + # with a dependent child/parent only; $3,000 when there is a + # dependent spouse, or with a spouse and a dependent child/parent. + # Per 51.5(4) a dependent spouse can be an ineligible-but-financially- + # dependent spouse. Apply the $3,000 marital-unit limit whenever the + # recipient lives with any spouse — federal joint SSI claim is too + # narrow because it requires both spouses to be SSI-categorically + # eligible. individual_resources = person("ssi_countable_resources", period.this_year) - joint = person("ssi_claim_is_joint", period.this_year) - # For joint SSI claims, federal SSI counts resources of both spouses - # against the couple limit. Mirror that rule: compare the combined - # marital-unit resources to the couple limit rather than each - # individual amount to the couple limit (which would effectively - # allow $3,000 per spouse). - couple_resources = person.marital_unit.sum(individual_resources) - resources_to_check = where(joint, couple_resources, individual_resources) + marital_resources = person.marital_unit.sum(individual_resources) + has_spouse = person.marital_unit.nb_persons() > 1 + resources_to_check = where(has_spouse, marital_resources, individual_resources) p = parameters(period).gov.ssa.ssi.eligibility.resources.limit - limit = where(joint, p.couple, p.individual) + limit = where(has_spouse, p.couple, p.individual) return resources_to_check <= limit diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py index 1e4404e5c59..c7bf4496361 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py @@ -13,18 +13,25 @@ class ia_ssa_smme_eligible(Variable): ) def formula(person, period, parameters): + # IAC 441—51.7(6): "Income of a recipient" must exceed 120% of the + # federal poverty level. The test is on the SSI claimant's own (or + # joint claim couple's) income, not on a larger SPM unit, so size + # the FPL by the SSI claim — 1 person for an individual, 2 for a + # joint claim — rather than by SPM unit size. aged_or_disabled = person("is_ssi_aged_blind_disabled", period.this_year) has_medicaid = person("ia_ssa_has_full_medicaid", period) has_medicare = person("ia_ssa_has_medicare_part_b", period) - # IAC 441—51.7(6): income must exceed 120% of the federal poverty - # level. SMME is a $1 technical SSP pathway for people categorically - # SSI-eligible but income-ineligible, so the FPL floor is what - # distinguishes them from regular SSI recipients. p = parameters(period).gov.states.ia.hhs.ssa + p_fpg = parameters(period).gov.hhs.fpg countable_monthly = ( person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR ) - fpg_monthly = person.spm_unit("spm_unit_fpg", period.this_year) / MONTHS_IN_YEAR + state_group = person.household("state_group_str", period.this_year) + first_person = p_fpg.first_person[state_group] + additional_person = p_fpg.additional_person[state_group] + joint_claim = person("ssi_claim_is_joint", period.this_year) + annual_fpg = first_person + where(joint_claim, additional_person, 0) + fpg_monthly = annual_fpg / MONTHS_IN_YEAR income_above_fpl_floor = ( countable_monthly > p.smme.minimum_income_fpl_multiplier * fpg_monthly ) From de46a32f2adfea33b0bf9a22e6d78139ac84edac Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 4 May 2026 15:18:03 -0400 Subject: [PATCH 16/23] Fix Pavel P2: pre-2017 IA SSA crashes and earned-side $20 disregard add-back MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 2011 historical values to dp/dependent_income_limit ($344, verified from SSA 2011 Iowa Table 1 Code C state portion = $1,018 - $674 FBR), smme/amount ($1 token, SMME enacted by 2004 Iowa Acts ch. 1085), and smme/minimum_income_fpl_multiplier (1.2, 120% FPL test in Iowa Code 249.3(4)(g) since 2004). Eliminates ParameterNotFoundError on pre-2017 RCF/Blind/etc. simulations where these values are read unconditionally. - Restore the earned-income portion of the SSI $20 general disregard add-back per 20 CFR § 416.1112: when unearned < $20, the leftover applies inside the earned flat ($65 + leftover) and is then reduced by the 50% earned-share rule. The helper now adds back applied_to_unearned + applied_to_earned * (1 - earned_share) instead of only min(unearned, $20). Verified against GL 6-B-46 p. 55 example ($500/mo earned -> RCF countable $977 = SSI standard + $10). - Tests: add 2011 RCF historical regression and a $500/mo earned-only RCF case that matches the manual's $977 countable income walkthrough. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia/hhs/ssa/dp/dependent_income_limit.yaml | 5 ++ .../gov/states/ia/hhs/ssa/smme/amount.yaml | 7 +- .../smme/minimum_income_fpl_multiplier.yaml | 7 +- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 75 +++++++++++++++++++ .../ia_ssa_countable_income_no_disregard.py | 45 +++++++---- 5 files changed, 122 insertions(+), 17 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml index b7d2aedb5fb..596bf260713 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml @@ -1,6 +1,11 @@ description: Iowa limits a dependent relative's countable income to this amount for dependent person eligibility under the State Supplementary Assistance program. values: + # IAC 441—51.5(1): the dependent income limit equals the state portion of + # the AGED_OR_DISABLED_WITH_DEPENDENT assistance standard (total minus + # individual FBR). 2011 SSA report Table 1 (Code C aged/disabled) confirms + # state portion $344 ($1,018 total - $674 individual FBR). + 2011-01-01: 344 2017-01-01: 379 2018-01-01: 387 2025-01-01: 503 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml index 1cbb2a2574c..9912d4d4ef7 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/amount.yaml @@ -1,7 +1,12 @@ description: Iowa provides this amount as the supplement for Medicare and Medicaid eligibles under the State Supplementary Assistance program. values: - 2017-01-01: 1 + # SMME was added by 2004 Iowa Acts ch. 1085 (§4) at Iowa Code 249.3(4) as a + # technical token payment whose purpose is to bring Medicare premium + # payments under federal financial participation. The $1 token amount has + # been published since at least 2017; carried back to the program's + # earliest in-model date. + 2011-01-01: 1 metadata: unit: currency-USD diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml index f5ced35272d..0aaf21ce96a 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme/minimum_income_fpl_multiplier.yaml @@ -1,7 +1,10 @@ description: Iowa uses this share of the federal poverty level as the minimum income threshold for supplement for Medicare and Medicaid eligibles under the State Supplementary Assistance program. values: - 2017-01-01: 1.2 + # Iowa Code 249.3(4)(g): "income of at least one hundred twenty percent of + # the federal poverty level". This 120% FPL test has been in statute since + # 2004 Iowa Acts ch. 1085 (§4) when SMME was created. + 2011-01-01: 1.2 metadata: unit: /1 @@ -12,3 +15,5 @@ metadata: href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 - title: Iowa Administrative Code 441—51.6(6), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=114 + - title: Iowa Code 249.3(4)(g) + href: https://www.legis.iowa.gov/docs/code/249.3.pdf diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml index f46e48374b8..06e74a99cf9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml @@ -1598,3 +1598,78 @@ output: ia_ssa_living_arrangement: [SMME] ia_ssa: [1] + +# ============================================================================ +# Pre-2017 historical and earned-income SSI-disregard regression tests. +# ============================================================================ + +- name: Case 8 historical, 2011 RCF resident with no other income. + period: 2011-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 20.00 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # 2011 individual FBR $674, RCF max_per_diem $28.14, PNA $93. SSI fills + # to FBR -> total_rcf_income $674; client participation $674 - $93 = + # $581. Cost-of-care 31 * min($20, $28.14) = $620. Supplement $620 - + # $581 = $39. Verifies 2011 lookups succeed (dependent_income_limit and + # SMME parameters now have 2011 historical values to prevent + # ParameterNotFoundError). + ssi: [674] + ia_ssa_living_arrangement: [RCF] + ia_ssa: [39] + +- name: Case 13 RCF earned-income, no-disregard add-back applies the leftover-20 dollars to earnings at half rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 6_000 # $500/mo earned, no unearned + ia_ssa_resides_in_residential_care_facility: true + ia_ssa_rcf_cost_per_diem: 37.60 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: IA + output: + # $500/mo earned, $0 unearned. SSI exclusions: $20 general falls into + # the earned flat ($65 + $20 = $85), then 50% of remainder. SSI + # countable_earned = ($500 - $85) * 0.5 = $207.50. SSI fills to + # $967 - $207.50 = $759.50. For RCF (no $20 disregard): add back + # $20 * 0.5 = $10 (the leftover applied to earned, halved by the 50% + # earned-share rule). Iowa countable = $217.50 (matches GL 6-B-46 p. + # 55: "an SSI recipient ... with earned income of more than $85 per + # month will commonly have countable income ... equal to the SSI + # payment standard plus $10 ($977)"). Total RCF income $977; client + # participation $977 - $126 = $851. Cost-of-care 31 * $37.60 = + # $1,165.60. Supplement = $1,165.60 - $851 = $314.60. + ia_ssa: [314.60] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py index 617d331a16e..0ef6b01ebd1 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py @@ -12,19 +12,22 @@ class ia_ssa_countable_income_no_disregard(Variable): "https://hhs.iowa.gov/media/15607/download", "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2", "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2", + "https://www.law.cornell.edu/cfr/text/20/416.1112", ) def formula(person, period, parameters): - # GL 6-B-46 pp. 30, 36–38, 54–58: Iowa RCF, FLH-eligibility, and IHHRC - # do not allow the SSI $20 general income disregard. ssi_countable_income - # already applies that exclusion (in _apply_ssi_exclusions), so add back - # the amount that was actually applied. + # Iowa RCF and IHHRC do not allow the SSI $20 general income + # disregard (GL 6-B-46 pp. 36, 54-58). ssi_countable_income already + # applies the disregard in _apply_ssi_exclusions, so reverse what + # SSI actually applied per 20 CFR § 416.1112: the $20 falls first on + # unearned, and any leftover goes inside the earned flat exclusion + # ($65 + leftover) before the 50% earned-share rule. The earned-side + # add-back is therefore halved by (1 − earned_share). # - # When both spouses are SSI-eligible (couple computation applies), SSI - # applies the $20 once to combined unearned and then splits the result - # evenly across the two spouses; the per-person add-back is then half - # of min(combined_unearned, $20). Otherwise the $20 applies to this - # person's own unearned income. + # When the SSI couple computation applies, _apply_ssi_exclusions runs + # on combined marital-unit income and the result is split per spouse, + # so size the add-back by combined income and divide by marital-unit + # size. p = parameters(period).gov.ssa.ssi.income.exclusions countable_monthly = ( person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR @@ -32,12 +35,24 @@ def formula(person, period, parameters): own_unearned_monthly = ( person("ssi_unearned_income", period.this_year) / MONTHS_IN_YEAR ) + own_earned_monthly = max_( + person("ssi_earned_income", period.this_year) / MONTHS_IN_YEAR, 0 + ) couple = person("ssi_couple_computation_applies", period.this_year) - combined_unearned_monthly = person.marital_unit.sum(own_unearned_monthly) - addback = where( + nb_in_unit = person.marital_unit.nb_persons() + unearned = where( + couple, + person.marital_unit.sum(own_unearned_monthly), + own_unearned_monthly, + ) + earned = where( couple, - min_(combined_unearned_monthly, p.general) - / person.marital_unit.nb_persons(), - min_(own_unearned_monthly, p.general), + person.marital_unit.sum(own_earned_monthly), + own_earned_monthly, ) - return countable_monthly + addback + applied_to_unearned = min_(p.general, unearned) + leftover = p.general - applied_to_unearned + earned_above_flat = max_(earned - p.earned, 0) + applied_to_earned = min_(leftover, earned_above_flat) + addback = applied_to_unearned + applied_to_earned * (1 - p.earned_share) + return countable_monthly + where(couple, addback / nb_in_unit, addback) From a7ea19991467188211fec1a86a48ef2b980041ad Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 4 May 2026 15:33:20 -0400 Subject: [PATCH 17/23] Use SSI's actual exclusion base for the IA SSA no-disregard add-back MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper reconstructs where the SSI $20 general exclusion landed, so its inputs must mirror _apply_ssi_exclusions exactly: marital unearned + parent deemed + ISM on the unearned side, and marital earned − blind/disabled working-student exclusion on the earned side. The previous version saw only ssi_unearned_income / ssi_earned_income, so it under-detected when the $20 landed on ISM or parental-deemed unearned income (e.g., $100/mo ISM with $500/mo earnings under-counted client participation by $10/mo). Also drops redundant period.this_year / MONTHS_IN_YEAR conversions on flow variables — period auto-converts annual flows to monthly inside a MONTH formula. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia_ssa_countable_income_no_disregard.py | 59 ++++++++----------- 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py index 0ef6b01ebd1..42ba67d8553 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_income_no_disregard.py @@ -16,43 +16,32 @@ class ia_ssa_countable_income_no_disregard(Variable): ) def formula(person, period, parameters): - # Iowa RCF and IHHRC do not allow the SSI $20 general income - # disregard (GL 6-B-46 pp. 36, 54-58). ssi_countable_income already - # applies the disregard in _apply_ssi_exclusions, so reverse what - # SSI actually applied per 20 CFR § 416.1112: the $20 falls first on - # unearned, and any leftover goes inside the earned flat exclusion - # ($65 + leftover) before the 50% earned-share rule. The earned-side - # add-back is therefore halved by (1 − earned_share). - # - # When the SSI couple computation applies, _apply_ssi_exclusions runs - # on combined marital-unit income and the result is split per spouse, - # so size the add-back by combined income and divide by marital-unit - # size. + # Iowa RCF and IHHRC do not allow the SSI $20 general income disregard + # (GL 6-B-46 pp. 36, 54-58). Reverse what _apply_ssi_exclusions + # actually applied. The exclusion bases must mirror + # ssi_countable_income exactly: unearned = marital unearned + parent + # deemed + ISM; earned = marital earned − blind/disabled working + # student exclusion (clamped at 0). The $20 falls first on the + # unearned base; any leftover applies inside the earned flat exclusion + # ($65 + leftover) before the 50% earned-share rule, so the + # earned-side add-back is reduced by (1 − earned_share). Couple + # computation halves countable per person; mirror that by dividing + # the add-back by marital-unit size when it applies. p = parameters(period).gov.ssa.ssi.income.exclusions - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR + countable_monthly = person("ssi_countable_income", period) + marital_unearned = person("ssi_marital_unearned_income", period) + parent_deemed = person( + "ssi_unearned_income_deemed_from_ineligible_parent", period ) - own_unearned_monthly = ( - person("ssi_unearned_income", period.this_year) / MONTHS_IN_YEAR - ) - own_earned_monthly = max_( - person("ssi_earned_income", period.this_year) / MONTHS_IN_YEAR, 0 - ) - couple = person("ssi_couple_computation_applies", period.this_year) - nb_in_unit = person.marital_unit.nb_persons() - unearned = where( - couple, - person.marital_unit.sum(own_unearned_monthly), - own_unearned_monthly, - ) - earned = where( - couple, - person.marital_unit.sum(own_earned_monthly), - own_earned_monthly, - ) - applied_to_unearned = min_(p.general, unearned) + ism = person("ssi_in_kind_support_and_maintenance", period) + unearned_basis = marital_unearned + parent_deemed + ism + marital_earned = person("ssi_marital_earned_income", period) + student_excl = person("ssi_blind_or_disabled_working_student_exclusion", period) + earned_basis = max_(marital_earned - student_excl, 0) + applied_to_unearned = min_(p.general, unearned_basis) leftover = p.general - applied_to_unearned - earned_above_flat = max_(earned - p.earned, 0) - applied_to_earned = min_(leftover, earned_above_flat) + applied_to_earned = min_(leftover, max_(earned_basis - p.earned, 0)) addback = applied_to_unearned + applied_to_earned * (1 - p.earned_share) + couple = person("ssi_couple_computation_applies", period.this_year) + nb_in_unit = person.marital_unit.nb_persons() return countable_monthly + where(couple, addback / nb_in_unit, addback) From 0bcf7fa91d81a863296097fa9016c0fa0ec1059a Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 4 May 2026 16:32:27 -0400 Subject: [PATCH 18/23] Address review findings on IA SSA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove ungrounded $22 blind add-on from FLH supplement (IAC 441-52.1(4) excludes the $22 standard for recipients of any other SSP); replace fragile float-equality with tolerance-based gap branch. - Fix three PDF page anchors: ihhrc/max_cost_single 4→5, rcf/days_multiplier 2→1, and rcf/ia_ssa_resides_in_residential_care_facility.py 2→1. - Fix dp/dependent_income_limit.yaml 2017 supplement section title from 441-51.5(1) to 441-51.4(1). - Refactor: replace 3 input booleans with one ia_ssa_living_arrangement_input enum, matching the MA/MI/AK/CT/IN state SSP pattern. Net -2 files. - Update Case 7 expected value $164 → $162 to reflect the FLH blind add-on removal. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia/hhs/ssa/dp/dependent_income_limit.yaml | 4 +- .../ia/hhs/ssa/ihhrc/max_cost_single.yaml | 2 +- .../ia/hhs/ssa/rcf/days_multiplier.yaml | 2 +- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 81 +++++++++---------- .../ia/hhs/ssa/ia_ssa_living_arrangement.yaml | 38 ++------- .../flh/ia_ssa_resides_in_family_life_home.py | 12 --- .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 16 ++-- .../ia/hhs/ssa/ia_ssa_living_arrangement.py | 8 +- .../ssa/ia_ssa_living_arrangement_input.py | 23 ++++++ .../ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py | 6 +- ...a_ssa_needs_in_home_health_related_care.py | 12 --- ...sa_resides_in_residential_care_facility.py | 13 --- 12 files changed, 86 insertions(+), 131 deletions(-) delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_resides_in_family_life_home.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement_input.py delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_needs_in_home_health_related_care.py delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_resides_in_residential_care_facility.py diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml index 596bf260713..039ca9054e8 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml @@ -1,7 +1,7 @@ description: Iowa limits a dependent relative's countable income to this amount for dependent person eligibility under the State Supplementary Assistance program. values: - # IAC 441—51.5(1): the dependent income limit equals the state portion of + # IAC 441—51.4(1): the dependent income limit equals the state portion of # the AGED_OR_DISABLED_WITH_DEPENDENT assistance standard (total minus # individual FBR). 2011 SSA report Table 1 (Code C aged/disabled) confirms # state portion $344 ($1,018 total - $674 individual FBR). @@ -16,7 +16,7 @@ metadata: period: month label: Iowa SSA dependent person dependent income limit reference: - - title: Iowa Administrative Code 441—51.5(1), January 4, 2017 supplement + - title: Iowa Administrative Code 441—51.4(1), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 - title: Iowa Administrative Code 441—52.1(2) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml index c474a5ce287..a126eb7b2d0 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc/max_cost_single.yaml @@ -11,6 +11,6 @@ metadata: - title: Iowa Administrative Code 441—177.4(1)(f) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2 - title: Iowa Administrative Code 441—177.10(3) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=4 + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=5 - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 in-home health care href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml index f3b9a90d63c..ef41744f615 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf/days_multiplier.yaml @@ -11,6 +11,6 @@ metadata: - title: Iowa Administrative Code 441—51.4(3) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 - title: Iowa Administrative Code 441—52.1(3) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2 + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - title: Iowa Administrative Code 441—51.4(3), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml index 06e74a99cf9..57e22a1738a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml @@ -99,7 +99,7 @@ age: 70 is_blind: true employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 37.60 marital_units: marital_unit: @@ -539,7 +539,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_family_life_home: true + ia_ssa_living_arrangement_input: FAMILY_LIFE_HOME marital_units: marital_unit: members: [person1] @@ -571,7 +571,6 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_family_life_home: false marital_units: marital_unit: members: [person1] @@ -596,7 +595,7 @@ age: 70 employment_income: 0 ssi_countable_resources: 5_000 - ia_ssa_resides_in_family_life_home: true + ia_ssa_living_arrangement_input: FAMILY_LIFE_HOME marital_units: marital_unit: members: [person1] @@ -623,7 +622,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_family_life_home: true + ia_ssa_living_arrangement_input: FAMILY_LIFE_HOME marital_units: marital_unit: members: [person1] @@ -650,7 +649,7 @@ person1: age: 70 social_security_retirement: 12_840 # $1,070/mo gross - ia_ssa_resides_in_family_life_home: true + ia_ssa_living_arrangement_input: FAMILY_LIFE_HOME marital_units: marital_unit: members: [person1] @@ -678,7 +677,7 @@ person1: age: 70 social_security_retirement: 14_400 # $1,200/mo gross - ia_ssa_resides_in_family_life_home: true + ia_ssa_living_arrangement_input: FAMILY_LIFE_HOME marital_units: marital_unit: members: [person1] @@ -696,7 +695,7 @@ # Countable $1,180/mo; standard $1,129; raw = max(0, 1129 - 1180) = 0. ia_ssa: [0] -- name: Case 7, blind FLH resident gets max_supplement plus 22 dollar blind increment. +- name: Case 7, blind FLH resident gets FLH benefit only without 22 dollar add-on. period: 2025-01 absolute_error_margin: 0.01 input: @@ -705,7 +704,7 @@ age: 40 is_blind: true employment_income: 0 - ia_ssa_resides_in_family_life_home: true + ia_ssa_living_arrangement_input: FAMILY_LIFE_HOME marital_units: marital_unit: members: [person1] @@ -720,12 +719,12 @@ members: [person1] state_code: IA output: - # POMS OS code I (FLH blind): state portion = max_supplement $142 plus - # $22 blind increment = $164. The blind increment replaces the - # Department top-up ($22 > $20), so Department does not pay a top-up - # on top. + # IAC 441-52.1(4): the $22 blind standard is for a blind recipient "not + # receiving another type of state supplementary assistance" — mutually + # exclusive with FLH, so the add-on does NOT stack. SSI-only recipient + # still gets the $20 Department top-up: max_supplement $142 + $20 gap = $162. ia_ssa_living_arrangement: [FLH] - ia_ssa: [164] + ia_ssa: [162] # ============================================================================ # IHHRC (In-Home Health-Related Care) supplement tests (IAC 441—177). @@ -750,7 +749,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 450 marital_units: marital_unit: @@ -777,7 +776,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 600 marital_units: marital_unit: @@ -803,7 +802,6 @@ person1: age: 70 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: false ia_ssa_ihhrc_cost_of_care: 400 marital_units: marital_unit: @@ -829,7 +827,7 @@ age: 70 employment_income: 0 ssi_countable_resources: 5_000 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 marital_units: marital_unit: @@ -857,12 +855,12 @@ person1: age: 70 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 900 person2: age: 68 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 900 marital_units: marital_unit: @@ -892,12 +890,12 @@ person1: age: 70 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 1_500 person2: age: 68 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 1_500 marital_units: marital_unit: @@ -926,12 +924,11 @@ person1: age: 70 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 800 person2: age: 68 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: false ia_ssa_ihhrc_cost_of_care: 0 marital_units: marital_unit: @@ -959,7 +956,7 @@ person1: age: 70 social_security_retirement: 20_000 # $1,667/mo gross - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 marital_units: marital_unit: @@ -988,7 +985,7 @@ person1: age: 70 social_security_retirement: 9_600 # $800/mo gross - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 marital_units: marital_unit: @@ -1017,12 +1014,12 @@ person1: age: 70 social_security_retirement: 7_200 # $600/mo gross - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 person2: age: 68 social_security_retirement: 7_200 # $600/mo gross - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 marital_units: marital_unit: @@ -1053,12 +1050,12 @@ person1: age: 70 social_security_retirement: 15_840 # $1,320/mo gross - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 person2: age: 68 social_security_retirement: 15_840 # $1,320/mo gross - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 marital_units: marital_unit: @@ -1090,12 +1087,11 @@ # $800/mo unearned per spouse; couple-combined ~$1,580 countable # after the $20 disregard, exceeding the couple FBR $1,450 by $130. social_security_retirement: 9_600 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 person2: age: 68 social_security_retirement: 9_600 - ia_ssa_needs_in_home_health_related_care: false ia_ssa_ihhrc_cost_of_care: 0 marital_units: marital_unit: @@ -1135,7 +1131,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 37.60 marital_units: marital_unit: @@ -1167,7 +1163,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 50 marital_units: marital_unit: @@ -1193,7 +1189,6 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_residential_care_facility: false ia_ssa_rcf_cost_per_diem: 30 marital_units: marital_unit: @@ -1219,7 +1214,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 38.47 marital_units: marital_unit: @@ -1249,7 +1244,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 0 marital_units: marital_unit: @@ -1276,7 +1271,7 @@ person1: age: 70 social_security_retirement: 12_000 # $1,000/mo - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 37.60 marital_units: marital_unit: @@ -1307,7 +1302,7 @@ person1: age: 70 social_security_retirement: 30_000 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 37.60 marital_units: marital_unit: @@ -1335,7 +1330,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 30.60 marital_units: marital_unit: @@ -1366,7 +1361,7 @@ age: 70 employment_income: 0 ssi_countable_resources: 5_000 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 37.60 marital_units: marital_unit: @@ -1611,7 +1606,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 20.00 marital_units: marital_unit: @@ -1645,7 +1640,7 @@ person1: age: 70 employment_income: 6_000 # $500/mo earned, no unearned - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 37.60 marital_units: marital_unit: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml index 6573f32780d..84757ed8002 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml @@ -13,7 +13,7 @@ age: 70 is_blind: true employment_income: 0 - ia_ssa_resides_in_residential_care_facility: true + ia_ssa_living_arrangement_input: RESIDENTIAL_CARE_FACILITY ia_ssa_rcf_cost_per_diem: 37.60 marital_units: marital_unit: @@ -40,7 +40,7 @@ age: 40 is_blind: true employment_income: 0 - ia_ssa_resides_in_family_life_home: true + ia_ssa_living_arrangement_input: FAMILY_LIFE_HOME marital_units: marital_unit: members: [person1] @@ -111,34 +111,6 @@ output: ia_ssa_living_arrangement: [NONE] -- name: Case 5, FLH resident who also needs IHHRC gets FLH (IAC 441-177.4(1)(c) own-home rule). - period: 2025-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - employment_income: 0 - ia_ssa_resides_in_family_life_home: true - ia_ssa_needs_in_home_health_related_care: true - ia_ssa_ihhrc_cost_of_care: 400 - marital_units: - marital_unit: - members: [person1] - tax_units: - tax_unit: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: IA - output: - # IHHRC requires living in own home; FLH resident fails that check -> FLH wins - ia_ssa_living_arrangement: [FLH] - - name: Case 6, person needing IHHRC who is also blind gets IHHRC not BLIND. period: 2025-01 absolute_error_margin: 0.01 @@ -148,7 +120,7 @@ age: 40 is_blind: true employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 marital_units: marital_unit: @@ -175,7 +147,7 @@ person1: age: 70 employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT ia_ssa_dp_has_eligible_dependent: true @@ -295,7 +267,7 @@ # Part B to test that IHHRC still wins over SMME. Use zero income # so IHHRC wins even though SMME condition could apply. employment_income: 0 - ia_ssa_needs_in_home_health_related_care: true + ia_ssa_living_arrangement_input: IN_HOME_HEALTH_RELATED_CARE ia_ssa_ihhrc_cost_of_care: 400 ia_ssa_has_full_medicaid: true ia_ssa_has_medicare_part_b: true diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_resides_in_family_life_home.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_resides_in_family_life_home.py deleted file mode 100644 index a83c515782b..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/flh/ia_ssa_resides_in_family_life_home.py +++ /dev/null @@ -1,12 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_resides_in_family_life_home(Variable): - value_type = bool - entity = Person - definition_period = MONTH - label = "Iowa SSA resides in certified family-life home" - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1" - ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index 7f69070272a..e71750ae6aa 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -62,23 +62,19 @@ def formula(person, period, parameters): # The $142 SSA cap caps the federally-administered piece; for SSI-only # recipients (no unearned income to absorb the $20 disregard), the # Department pays the (state_supplement − cap) gap so total income - # reaches the standard. The blind increment ($22) replaces this gap - # payment for blind recipients. + # reaches the standard (GL 6-B-46 p.30). 441—52.1(4) excludes the $22 + # blind allowance for recipients of any other SSP, so blind FLH + # recipients receive the FLH benefit only — no $22 stack. flh_v_shape = max_( 0, (individual_fbr + p.flh.state_supplement) - max_(countable_monthly, individual_fbr), ) flh_base = min_(flh_v_shape, p.flh.max_supplement) - is_blind = person("is_blind", period.this_year) flh_extra = where( - is_blind, - p.blind, - where( - countable_monthly == 0, - max_(0, p.flh.state_supplement - p.flh.max_supplement), - 0, - ), + countable_monthly < 0.01, + max_(0, p.flh.state_supplement - p.flh.max_supplement), + 0, ) flh_amt = flh_base + flh_extra # RCF — IAC 441—52.1(3): cost-of-care minus client participation. diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py index af700f8a8a5..d57dc916116 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py @@ -42,10 +42,12 @@ def formula(person, period, parameters): rcf_client_participation = max_( 0, rcf_total_income - p.rcf.personal_needs_allowance ) - in_rcf = person("ia_ssa_resides_in_residential_care_facility", period) + arrangement_input = person("ia_ssa_living_arrangement_input", period) + arr_input_values = arrangement_input.possible_values + in_rcf = arrangement_input == arr_input_values.RESIDENTIAL_CARE_FACILITY rcf_income_threshold = p.rcf.days_multiplier * p.rcf.max_per_diem rcf_income_eligible = rcf_client_participation < rcf_income_threshold - needs_ihhrc = person("ia_ssa_needs_in_home_health_related_care", period) + needs_ihhrc = arrangement_input == arr_input_values.IN_HOME_HEALTH_RELATED_CARE both_need_care = person("ia_ssa_ihhrc_both_need_care", period) # IAC 441—177.4(1)(f) caps combined marital-unit countable income at # $480.55 (one spouse needs care) or $961.10 (both need care) after @@ -59,7 +61,7 @@ def formula(person, period, parameters): both_need_care, p.ihhrc.max_cost_couple, p.ihhrc.max_cost_single ) ihhrc_income_eligible = ihhrc_countable_after_disregard <= ihhrc_cap - in_flh = person("ia_ssa_resides_in_family_life_home", period) + in_flh = arrangement_input == arr_input_values.FAMILY_LIFE_HOME # IAC 441—177.4(1)(c): IHHRC recipients must live in their own home, # so exclude those residing in an RCF or family-life home. in_own_home = ~in_rcf & ~in_flh diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement_input.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement_input.py new file mode 100644 index 00000000000..6e323e7266b --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement_input.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class IASSALivingArrangementInput(Enum): + NONE = "Not in a qualifying arrangement" + FAMILY_LIFE_HOME = "Resides in certified family-life home" + RESIDENTIAL_CARE_FACILITY = "Resides in licensed residential care facility" + IN_HOME_HEALTH_RELATED_CARE = "Receives in-home health-related care" + + +class ia_ssa_living_arrangement_input(Variable): + value_type = Enum + entity = Person + definition_period = MONTH + label = "Iowa SSA living-arrangement input" + possible_values = IASSALivingArrangementInput + default_value = IASSALivingArrangementInput.NONE + defined_for = StateCode.IA + reference = ( + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1", + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2", + "https://www.legis.iowa.gov/docs/code/135C.1.pdf", + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py index d006f704db4..c7f0d502696 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_both_need_care.py @@ -12,5 +12,9 @@ class ia_ssa_ihhrc_both_need_care(Variable): ) def formula(person, period, parameters): - needs_care = person("ia_ssa_needs_in_home_health_related_care", period) + arrangement_input = person("ia_ssa_living_arrangement_input", period) + needs_care = ( + arrangement_input + == arrangement_input.possible_values.IN_HOME_HEALTH_RELATED_CARE + ) return person.marital_unit.sum(needs_care) == 2 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_needs_in_home_health_related_care.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_needs_in_home_health_related_care.py deleted file mode 100644 index cbb86aa4848..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_needs_in_home_health_related_care.py +++ /dev/null @@ -1,12 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_needs_in_home_health_related_care(Variable): - value_type = bool - entity = Person - definition_period = MONTH - label = "Iowa SSA needs in-home health-related care" - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2" - ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_resides_in_residential_care_facility.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_resides_in_residential_care_facility.py deleted file mode 100644 index 121b30f2451..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/rcf/ia_ssa_resides_in_residential_care_facility.py +++ /dev/null @@ -1,13 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_resides_in_residential_care_facility(Variable): - value_type = bool - entity = Person - definition_period = MONTH - label = "Iowa SSA resides in licensed residential care facility" - defined_for = StateCode.IA - reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=2", - "https://www.legis.iowa.gov/docs/code/135C.1.pdf", - ) From 58566d298068699c4a2bcfb7c1b1b5385a87bbb7 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 5 May 2026 00:03:35 -0400 Subject: [PATCH 19/23] Fix IA SSA formula bugs and address remaining /review-program findings Formula bugs uncovered while expanding test coverage: * IHHRC supplement was always zero in production. ia_ssa_ihhrc_cost_of_care had no formula, so cost defaulted to zero and ihhrc_amt collapsed to max(0, 0 - participation) = 0. Add a formula that imputes max_cost_single when ia_ssa_living_arrangement is IHHRC; users can still override with actual care-cost data. * DP supplement double-attributed to spouses. When both spouses encoded the same couple-FBR DP configuration, both computed the full per-couple supplement and the SPM-unit total doubled. Add a per-marital-unit divisor guard that splits the supplement across claimants. * DP and SMME compared per-spouse income to couple-level thresholds. For joint SSI claims, ssi_countable_income returns combined / 2 per spouse, but the DP couple-FBR comparison and the SMME 2-person FPL gate were written against per-spouse values. Aggregate countable across the marital unit before the comparison when the threshold is couple-level. Reference and registry fixes: * dp/dependent_income_limit.yaml: cite operative IAC 441-51.5(1) and the HHS Manual; remove the misleading 2018 Ch.52 reference. * flh/max_supplement.yaml: cite HHS Manual GL 6-B-46 page 31 for the $142 SSA-administered cap. * programs.yaml: add parameter_prefix to the IA SSA entry. Code cleanup: drop the redundant period.this_year / MONTHS_IN_YEAR pattern in favor of period directly. PolicyEngine auto-divides FLOW-type YEAR variables when accessed at a MONTH period. New tests (Cases 9-14 in ia_ssa.yaml): * Case 9 / 14: BLIND_WITH_DEPENDENT 2025 and 2011 (state portion matches SSA 2011 Iowa Table 1, Code C blind: $366). * Case 10: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT 2025. * Case 11: regression test for the marital-unit divisor when both spouses set the same couple-FBR DP config. * Case 12: regression test for joint-claim DP phaseout when combined income exceeds couple FBR. * Case 13: AGED_OR_DISABLED_WITH_DEPENDENT 2011 (state portion matches SSA 2011 Iowa Table 1, Code C aged: $344). All 88 IA SSA YAML tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ia/hhs/ssa/dp/dependent_income_limit.yaml | 10 +- .../states/ia/hhs/ssa/flh/max_supplement.yaml | 2 + policyengine_us/programs.yaml | 1 + .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 282 ++++++++++++++++++ .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 26 +- .../ia/hhs/ssa/ia_ssa_living_arrangement.py | 7 +- .../ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py | 12 + .../ia/hhs/ssa/smme/ia_ssa_smme_eligible.py | 19 +- 8 files changed, 336 insertions(+), 23 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml index 039ca9054e8..959b5dedbae 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dp/dependent_income_limit.yaml @@ -16,13 +16,11 @@ metadata: period: month label: Iowa SSA dependent person dependent income limit reference: + - title: Iowa Administrative Code 441—51.5(1) (dependent relative income test) + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2 - title: Iowa Administrative Code 441—51.4(1), January 4, 2017 supplement href: https://www.legis.iowa.gov/docs/aco/supplement/01-04-2017.pdf#page=113 - - title: Iowa Administrative Code 441—52.1(2) - href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - - title: Iowa Administrative Code 441—52.1, March 28, 2018 rule update - href: https://www.legis.iowa.gov/docs/iac/rule/03-28-2018.441.52.1.pdf#page=1 - - title: Iowa HHS General Letter 6-B-46 (effective January 1, 2025) - href: https://hhs.iowa.gov/media/15607/download + - title: Iowa HHS Employees' Manual Title 6 Chapter B, Income (DP), p.15 + href: https://hhs.iowa.gov/media/15607/download#page=21 - title: Iowa HHS State Supplementary Assistance Standards (current) href: https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml index 1f9ec6b3c30..323f3aab0f6 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/flh/max_supplement.yaml @@ -8,6 +8,8 @@ metadata: period: month label: Iowa SSA family-life home maximum supplement reference: + - title: Iowa HHS Employees' Manual Title 6 Chapter B, Making the Family-Life Home Payment, p.31 + href: https://hhs.iowa.gov/media/15607/download#page=37 - title: Iowa Administrative Code 441—52.1(1) href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf#page=1 - title: SSA State Assistance Programs for SSI Recipients — Iowa (January 2011), Table 1 OS code D aged diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index bb09bebb0bb..4e1bd162d90 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -637,6 +637,7 @@ programs: name: Iowa SSA full_name: Iowa State Supplementary Assistance variable: ia_ssa + parameter_prefix: gov.states.ia.hhs.ssa - state: ID status: complete name: Idaho AABD diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml index 57e22a1738a..2511541cb11 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml @@ -518,6 +518,247 @@ # max(0, 1470 - max(1280, 967)) = $190. ia_ssa: [190] +- name: Case 9, blind client with dependent uses single-client BLIND_WITH_DEPENDENT standard. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_blind: true + employment_income: 0 + ia_ssa_dp_configuration: BLIND_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person2: + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1] + second_marital_unit: + members: [person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # BLIND_WITH_DEPENDENT 2025 standard $1,492 - individual FBR $967 = $525. + ia_ssa_living_arrangement: [DP, NONE] + ia_ssa: [525, 0] + +- name: Case 10, blind client with blind spouse and dependent uses BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT standard. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + employment_income: 0 + ia_ssa_dp_configuration: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person2: + age: 68 + is_blind: true + employment_income: 0 + ia_ssa_dp_configuration: NONE + person3: + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1, person2] + second_marital_unit: + members: [person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: IA + output: + # person1: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT 2025 standard $1,997 - + # couple FBR $1,450 = $547 DP supplement. Only person1 sets the + # couple-FBR config (repo convention), marital-unit guard divides by 1. + # person2 has no DP/RCF/IHHRC/FLH but is_blind=true with $0 income, so + # the SELECT cascade routes her to BLIND ($22 federally-administered). + # person3: child, no SSP category. + ia_ssa_living_arrangement: [DP, BLIND, NONE] + ia_ssa: [547, 22, 0] + +- name: Case 11, both spouses set the same couple-FBR DP config — marital-unit guard prevents double-attribution. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person2: + age: 68 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person3: + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1, person2] + second_marital_unit: + members: [person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: IA + output: + # AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT 2025 standard $1,953 - + # couple FBR $1,450 = $503. Both spouses claim the couple config; the + # marital-unit guard splits the supplement so the SPM-unit total stays + # at $503 (each spouse gets $251.50), not $1,006. + ia_ssa: [251.5, 251.5, 0] + +- name: Case 12, joint-claim couple DP phases to zero when combined income exceeds couple FBR. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 14_400 # $1,200/mo each + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + is_ssi_aged_blind_disabled: true + ssi_claim_is_joint: true + person2: + age: 68 + social_security_retirement: 14_400 + ia_ssa_dp_configuration: NONE + is_ssi_aged_blind_disabled: true + ssi_claim_is_joint: true + person3: + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1, person2] + second_marital_unit: + members: [person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: IA + output: + # Combined SS $28,800/yr - $240 disregard = $28,560/yr countable couple. + # Combined monthly = $2,380 > couple FBR $1,450, so the supplement + # phases out: max(0, $1,953 standard - max($2,380, $1,450)) = $0. + # Without the marital-unit aggregation, the formula would compare the + # per-spouse half ($1,190) against the couple-level threshold and + # incorrectly pay the full $503. + ia_ssa: [0, 0, 0] + +- name: Case 13, 2011 aged-or-disabled-with-dependent — state portion matches SSA Table 1 ($344). + period: 2011-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person2: + # Dependent relative present in the household (per IAC 441—51.5(1)). + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1] + second_marital_unit: + members: [person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Iowa 2011 combined standard $1,018 - 2011 individual FBR $674 = $344 + # state portion (matches SSA 2011 Iowa report Table 1, Code C aged). + ia_ssa_living_arrangement: [DP, NONE] + ia_ssa: [344, 0] + +- name: Case 14, 2011 blind-with-dependent — state portion matches SSA Table 1 ($366). + period: 2011-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_blind: true + employment_income: 0 + ia_ssa_dp_configuration: BLIND_WITH_DEPENDENT + ia_ssa_dp_has_eligible_dependent: true + ia_ssa_dp_dependent_countable_income: 0 + person2: + # Dependent relative present in the household (per IAC 441—51.5(1)). + age: 10 + employment_income: 0 + marital_units: + first_marital_unit: + members: [person1] + second_marital_unit: + members: [person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # Iowa 2011 combined standard $1,040 - 2011 individual FBR $674 = $366 + # state portion (matches SSA 2011 Iowa report Table 1, Code C blind). + ia_ssa_living_arrangement: [DP, NONE] + ia_ssa: [366, 0] + # ============================================================================ # FLH (Family-Life Home) supplement tests (IAC 441—52.1(1)). # ============================================================================ @@ -1594,6 +1835,47 @@ ia_ssa_living_arrangement: [SMME] ia_ssa: [1] +- name: Case 8, aged married couple with joint SSI claim — SMME uses 2-person 120% FPL threshold. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + social_security_retirement: 14_400 # $1,200/mo each + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + is_ssi_aged_blind_disabled: true + ssi_claim_is_joint: true + person2: + age: 68 + social_security_retirement: 14_400 + ia_ssa_has_full_medicaid: true + ia_ssa_has_medicare_part_b: true + is_ssi_aged_blind_disabled: true + ssi_claim_is_joint: true + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # 2025 2-person FPL (contiguous) = $20,440/yr; 120% = $24,528/yr = + # $2,044/mo. Combined SS $28,800/yr - $20/mo couple disregard = ~$2,380/mo + # countable per spouse (joint claim). Above the 2-person 120% FPL gate. + # No federal SSI (countable > couple FBR $1,450). Each spouse gets $1 + # SMME so the SPM-unit total ia_ssa = $2. + ia_ssa_living_arrangement: [SMME, SMME] + ia_ssa: [1, 1] + # ============================================================================ # Pre-2017 historical and earned-income SSI-disregard regression tests. # ============================================================================ diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index e71750ae6aa..5938bf50d24 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -19,10 +19,10 @@ def formula(person, period, parameters): arrangement = person("ia_ssa_living_arrangement", period) arr_values = arrangement.possible_values p = parameters(period).gov.states.ia.hhs.ssa - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR - ) - ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR + # YEAR-defined FLOW variables auto-divide to monthly when requested + # at a MONTH period (policyengine-core simulation.calculate_divide). + countable_monthly = person("ssi_countable_income", period) + ssi_monthly = person("ssi", period) # Iowa RCF, FLH-eligibility, and IHHRC do not allow the SSI $20 general # income disregard (GL 6-B-46 pp. 30, 36–38, 54–58). RCF and IHHRC are # state-administered, so this helper restores the $20 the SSI exclusion @@ -53,10 +53,24 @@ def formula(person, period, parameters): | (dp_config == dp_config_values.BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT) ) dp_applicable_fbr = where(dp_has_spouse, couple_fbr, individual_fbr) - dp_amt = max_( + # Couple-config DP compares income against couple_fbr, which is a + # marital-unit-level threshold. countable_monthly is per-spouse + # (combined / 2 for joint SSI claims), so aggregate across the + # marital unit when the comparison threshold is couple-level. + marital_countable = person.marital_unit.sum(countable_monthly) + dp_compare_income = where(dp_has_spouse, marital_countable, countable_monthly) + dp_amt_full = max_( 0, - dp_assistance_standard - max_(countable_monthly, dp_applicable_fbr), + dp_assistance_standard - max_(dp_compare_income, dp_applicable_fbr), ) + # Per-marital-unit guard: couple-FBR DP configurations describe the + # whole marital unit, not each spouse. Split the supplement equally + # among spouses in the marital unit who claim a couple-FBR config so + # the SPM-unit aggregation does not double-count when both spouses + # set the same couple configuration. + dp_couple_count = person.marital_unit.sum(dp_has_spouse) + dp_divisor = where(dp_has_spouse, max_(dp_couple_count, 1), 1) + dp_amt = dp_amt_full / dp_divisor # FLH — IAC 441—52.1(1): SSA-administered, so the V-shape uses # ssi_countable_income (with the $20 disregard SSA actually applies). # The $142 SSA cap caps the federally-administered piece; for SSI-only diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py index d57dc916116..e911e55ea3e 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py @@ -24,10 +24,9 @@ class ia_ssa_living_arrangement(Variable): def formula(person, period, parameters): eligible = person("ia_ssa_eligible", period) p = parameters(period).gov.states.ia.hhs.ssa - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR - ) - ssi_monthly = person("ssi", period.this_year) / MONTHS_IN_YEAR + # YEAR-defined FLOW variables auto-divide to monthly at MONTH period. + countable_monthly = person("ssi_countable_income", period) + ssi_monthly = person("ssi", period) countable_no_disregard = person("ia_ssa_countable_income_no_disregard", period) p_ssi = parameters(period).gov.ssa.ssi.amount individual_fbr = p_ssi.individual diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py index 8fd70a1486d..1ad27fc1074 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ihhrc/ia_ssa_ihhrc_cost_of_care.py @@ -11,3 +11,15 @@ class ia_ssa_ihhrc_cost_of_care(Variable): reference = ( "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2" ) + + def formula(person, period, parameters): + # Iowa pays the eligible service cost above client participation, up + # to the per-person max payment of $480.55 (IAC 441—177.10(3); Iowa + # HHS 2026 standards). Actual care cost is a per-recipient input we + # do not track at the moment. When arrangement is known to be IHHRC + # but cost is unavailable, impute the cap so the supplement is not + # falsely zeroed; users can override with actual care-cost data. + p = parameters(period).gov.states.ia.hhs.ssa.ihhrc + arrangement = person("ia_ssa_living_arrangement", period) + in_ihhrc = arrangement == arrangement.possible_values.IHHRC + return where(in_ihhrc, p.max_cost_single, 0) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py index c7bf4496361..b731ff02b1a 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/smme/ia_ssa_smme_eligible.py @@ -15,22 +15,27 @@ class ia_ssa_smme_eligible(Variable): def formula(person, period, parameters): # IAC 441—51.7(6): "Income of a recipient" must exceed 120% of the # federal poverty level. The test is on the SSI claimant's own (or - # joint claim couple's) income, not on a larger SPM unit, so size - # the FPL by the SSI claim — 1 person for an individual, 2 for a - # joint claim — rather than by SPM unit size. + # joint-claim couple's) combined income, not on a larger SPM unit, + # so size the FPL by the SSI claim — 1 person for an individual, + # 2 for a joint claim — rather than by SPM unit size. For joint + # claims, ssi_countable_income returns the per-spouse half of the + # combined marital countable, so aggregate across the marital unit + # before comparing to the 2-person FPL. aged_or_disabled = person("is_ssi_aged_blind_disabled", period.this_year) has_medicaid = person("ia_ssa_has_full_medicaid", period) has_medicare = person("ia_ssa_has_medicare_part_b", period) p = parameters(period).gov.states.ia.hhs.ssa p_fpg = parameters(period).gov.hhs.fpg - countable_monthly = ( - person("ssi_countable_income", period.this_year) / MONTHS_IN_YEAR - ) + joint_claim = person("ssi_claim_is_joint", period.this_year) + # YEAR-defined FLOW vars auto-divide to monthly at MONTH period. + own_monthly = person("ssi_countable_income", period) + marital_monthly = person.marital_unit.sum(own_monthly) + countable_monthly = where(joint_claim, marital_monthly, own_monthly) state_group = person.household("state_group_str", period.this_year) first_person = p_fpg.first_person[state_group] additional_person = p_fpg.additional_person[state_group] - joint_claim = person("ssi_claim_is_joint", period.this_year) annual_fpg = first_person + where(joint_claim, additional_person, 0) + # FPG parameters are annual values (no auto-divide for parameters). fpg_monthly = annual_fpg / MONTHS_IN_YEAR income_above_fpl_floor = ( countable_monthly > p.smme.minimum_income_fpl_multiplier * fpg_monthly From f048d1bd5ffc6a02a56fcec8054a0ef6369d741a Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 5 May 2026 00:39:27 -0400 Subject: [PATCH 20/23] Fix IA SSA blind couple-FBR aggregation and FLH gap-based top-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BLIND: For joint SSI claims with both spouses blind, ssi_countable_income returns combined / 2 per spouse — so the previous per-spouse comparison against (individual_fbr + $22) admitted couples whose combined income exceeded the couple-level ceiling. Aggregate marital countable, compare against (couple_fbr + 2 × $22), then split equally to avoid SPM-unit double-counting (mirrors the DP couple-FBR fix). FLH: Replace the all-or-nothing $20 top-up (triggered whenever ssi_countable_income == 0) with a gap-based formula. Department fills the gap from total income to the FLH standard, so a recipient with $10/mo of other unearned income needs only a $10 top-up (was $20). Defensive cap at (state_supplement − max_supplement) so artificially low ssi_monthly cannot explode the supplement. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 54 +++++++++++++------ .../ia/hhs/ssa/ia_ssa_living_arrangement.py | 12 ++++- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index 5938bf50d24..d5cd4c14c0d 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -31,12 +31,26 @@ def formula(person, period, parameters): p_ssi = parameters(period).gov.ssa.ssi.amount individual_fbr = p_ssi.individual couple_fbr = p_ssi.couple - # BLIND — IAC 441—52.1(4): flat $22 state supplement (frozen since 2011). - # Federally administered, so SSA's $20 disregard applies via - # ssi_countable_income. - blind_amt = max_( - 0, (individual_fbr + p.blind) - max_(countable_monthly, individual_fbr) + joint_claim = person("ssi_claim_is_joint", period.this_year) + is_blind = person("is_blind", period.this_year) + marital_countable = person.marital_unit.sum(countable_monthly) + # BLIND — IAC 441—52.1(4): flat $22 state supplement (frozen since 2011) + # per blind person. Federally administered, so SSA's $20 disregard + # applies via ssi_countable_income. For joint SSI claims where both + # spouses are blind, ssi_countable_income returns combined / 2 per + # spouse, so aggregate marital countable and compare against + # (couple_fbr + 2 × $22), then split the result equally so the + # SPM-unit aggregation does not double-count. + blind_couple = joint_claim & (person.marital_unit.sum(is_blind) == 2) + blind_applicable_fbr = where(blind_couple, couple_fbr, individual_fbr) + blind_supplement_total = where(blind_couple, 2 * p.blind, p.blind) + blind_compare_income = where(blind_couple, marital_countable, countable_monthly) + blind_amt_full = max_( + 0, + (blind_applicable_fbr + blind_supplement_total) + - max_(blind_compare_income, blind_applicable_fbr), ) + blind_amt = blind_amt_full / where(blind_couple, 2, 1) # DP — IAC 441—52.1(2): per-configuration assistance standard. Pick the # applicable Federal Benefit Rate (couple FBR for configurations that # include an eligible spouse, individual FBR otherwise) so the @@ -57,7 +71,6 @@ def formula(person, period, parameters): # marital-unit-level threshold. countable_monthly is per-spouse # (combined / 2 for joint SSI claims), so aggregate across the # marital unit when the comparison threshold is couple-level. - marital_countable = person.marital_unit.sum(countable_monthly) dp_compare_income = where(dp_has_spouse, marital_countable, countable_monthly) dp_amt_full = max_( 0, @@ -73,22 +86,32 @@ def formula(person, period, parameters): dp_amt = dp_amt_full / dp_divisor # FLH — IAC 441—52.1(1): SSA-administered, so the V-shape uses # ssi_countable_income (with the $20 disregard SSA actually applies). - # The $142 SSA cap caps the federally-administered piece; for SSI-only - # recipients (no unearned income to absorb the $20 disregard), the - # Department pays the (state_supplement − cap) gap so total income - # reaches the standard (GL 6-B-46 p.30). 441—52.1(4) excludes the $22 - # blind allowance for recipients of any other SSP, so blind FLH - # recipients receive the FLH benefit only — no $22 stack. + # The $142 SSA cap caps the federally-administered piece; the + # Department fills the gap from total income to the FLH standard + # (GL 6-B-46 p.30) — so an SSI-only recipient gets the full + # (state_supplement − cap) top-up, while a recipient with $10/mo of + # other unearned income needs only a $10 top-up to reach the + # standard. 441—52.1(4) excludes the $22 blind allowance for + # recipients of any other SSP, so blind FLH recipients receive the + # FLH benefit only. flh_v_shape = max_( 0, (individual_fbr + p.flh.state_supplement) - max_(countable_monthly, individual_fbr), ) flh_base = min_(flh_v_shape, p.flh.max_supplement) - flh_extra = where( - countable_monthly < 0.01, + # non_ssi_income proxies gross other income via post-SSI-exclusion + # countable; pre-exclusion gross would be more accurate for cases + # with earned income (where the $65 + 50% earned exclusions hide + # gross from countable_no_disregard) — flag for follow-up. + non_ssi_income = max_(0, countable_no_disregard) + flh_total_income_after_base = ssi_monthly + non_ssi_income + flh_base + flh_standard = individual_fbr + p.flh.state_supplement + # Defensive cap at the published gap so artificially low ssi_monthly + # (non-takeup, mid-month transitions) cannot explode the supplement. + flh_extra = min_( + max_(0, flh_standard - flh_total_income_after_base), max_(0, p.flh.state_supplement - p.flh.max_supplement), - 0, ) flh_amt = flh_base + flh_extra # RCF — IAC 441—52.1(3): cost-of-care minus client participation. @@ -115,7 +138,6 @@ def formula(person, period, parameters): # are not modeled. ihhrc_cost = person("ia_ssa_ihhrc_cost_of_care", period) both_need_care = person("ia_ssa_ihhrc_both_need_care", period) - joint_claim = person("ssi_claim_is_joint", period.this_year) basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) combined_countable = person.marital_unit.sum(countable_no_disregard) combined_participation = max_(0, combined_countable - basic_ssi_disregard) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py index e911e55ea3e..404a5aa3e46 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py @@ -79,7 +79,17 @@ def formula(person, period, parameters): # supplement phases to zero when countable income reaches FBR + state # standard. Mirror that ceiling in the category gate so blind # recipients with excess income fall through to the next category. - blind_income_eligible = countable_monthly < individual_fbr + p.blind + # For joint SSI claims where both spouses are blind, + # ssi_countable_income returns combined / 2 per spouse, so aggregate + # marital countable and compare against (couple_fbr + 2 × $22). + blind_couple = joint_claim & (person.marital_unit.sum(is_blind) == 2) + marital_countable = person.marital_unit.sum(countable_monthly) + blind_applicable_fbr = where(blind_couple, couple_fbr, individual_fbr) + blind_supplement = where(blind_couple, 2 * p.blind, p.blind) + blind_compare_income = where(blind_couple, marital_countable, countable_monthly) + blind_income_eligible = ( + blind_compare_income < blind_applicable_fbr + blind_supplement + ) smme_eligible = person("ia_ssa_smme_eligible", period) return select( [ From 182798fdddb1a916398616f9c3a92ac7f8911c0b Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 5 May 2026 01:03:54 -0400 Subject: [PATCH 21/23] Fix IA SSA one-blind joint couples and unreachable Iowa marital resource limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BLIND one-blind joint: previous gate `joint_claim & sum(is_blind) == 2` only applied couple-FBR basis when both spouses were blind. For joint SSI claims with one blind spouse, ssi_countable_income still returns combined / 2 per spouse and the federal piece is paid against couple FBR, so the per-spouse comparison against individual FBR overpaid. Generalize: any joint claim uses (couple_fbr + N × $22) where N is the number of blind people in the marital unit; split only when both blind. Mirror the same logic in the living-arrangement gate. ia_ssa_eligible: replace federal `is_ssi_eligible` (which applies the $2,000 individual resource test for non-joint married claimants) with ABD + immigration + Iowa's own resource test. Iowa's $3,000 marital limit (IAC 441—51.5(2)) was unreachable for cases like a claimant with $2,500 marital resources and a non-ABD spouse. IAC 441—51.1 lets Iowa pay recipients who would qualify for SSI except for excess income, so the federal resource test should not gate Iowa eligibility. Adds Cases 15-16 as regression tests for both fixes. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 84 +++++++++++++++++++ .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 26 +++--- .../gov/states/ia/hhs/ssa/ia_ssa_eligible.py | 19 ++++- .../ia/hhs/ssa/ia_ssa_living_arrangement.py | 15 ++-- 4 files changed, 125 insertions(+), 19 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml index 2511541cb11..3660c3cc100 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml @@ -1950,3 +1950,87 @@ # participation $977 - $126 = $851. Cost-of-care 31 * $37.60 = # $1,165.60. Supplement = $1,165.60 - $851 = $314.60. ia_ssa: [314.60] + +- name: Case 15 BLIND one-blind joint couple uses couple-FBR basis (regression for one-blind joint bug). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + is_ssi_aged_blind_disabled: true + social_security_retirement: 8_940 # $745/mo each, $1,490/mo combined + ssi_claim_is_joint: true + person2: + age: 70 + is_blind: false + is_ssi_aged_blind_disabled: true + social_security_retirement: 8_940 + ssi_claim_is_joint: true + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # 2025: individual FBR $967, couple FBR $1,450. Combined gross unearned + # $1,490/mo. After SSI $20 GIE, combined countable = $1,470/mo + # ($735/mo per spouse via joint-claim attribution). + # Pre-fix bug: per-spouse comparison $735 < $967 + $22 → person1 receives + # full $22 even though combined > couple FBR. + # Post-fix: marital comparison $1,470 vs $1,450 + 1×$22 = $1,472. + # supplement = $1,472 - max($1,470, $1,450) = $2 → person1 ia_ssa = $2. + # person2 (not blind, no other category) routes to NONE. + ia_ssa_living_arrangement: [BLIND, NONE] + ia_ssa: [2, 0] + +- name: Case 16 Iowa $3,000 marital resource limit reachable for non-joint married claimant (regression for federal $2,000 over-gating). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: true + is_ssi_aged_blind_disabled: true + ssi_countable_resources: 2_500 + ssi_claim_is_joint: false + person2: + age: 50 + is_ssi_aged_blind_disabled: false + ssi_countable_resources: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IA + output: + # IAC 441—51.5(2): Iowa allows $3,000 marital-unit resources when the + # claimant lives with a (potentially ineligible) spouse. Federal SSI + # applies $2,000 individual when not in a joint claim; person1's $2,500 + # alone fails federal resource test (ssi = 0) but Iowa's $3,000 limit + # is satisfied ($2,500 ≤ $3,000), so ia_ssa_eligible holds and the + # blind branch pays the $22 state supplement. + # Pre-fix bug: ia_ssa_eligible AND'd with is_ssi_eligible (federal + # individual $2,000 test) → False → no Iowa SSP. + # Post-fix: ABD + immigration + Iowa resource test → True. + ia_ssa_eligible: [true, false] + ia_ssa_living_arrangement: [BLIND, NONE] + ia_ssa: [22, 0] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index d5cd4c14c0d..aa021d7c611 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -36,21 +36,27 @@ def formula(person, period, parameters): marital_countable = person.marital_unit.sum(countable_monthly) # BLIND — IAC 441—52.1(4): flat $22 state supplement (frozen since 2011) # per blind person. Federally administered, so SSA's $20 disregard - # applies via ssi_countable_income. For joint SSI claims where both - # spouses are blind, ssi_countable_income returns combined / 2 per - # spouse, so aggregate marital countable and compare against - # (couple_fbr + 2 × $22), then split the result equally so the - # SPM-unit aggregation does not double-count. - blind_couple = joint_claim & (person.marital_unit.sum(is_blind) == 2) - blind_applicable_fbr = where(blind_couple, couple_fbr, individual_fbr) - blind_supplement_total = where(blind_couple, 2 * p.blind, p.blind) - blind_compare_income = where(blind_couple, marital_countable, countable_monthly) + # applies via ssi_countable_income. For any joint SSI claim + # ssi_countable_income returns combined / 2 per spouse and the + # federal piece is paid against couple_fbr, so aggregate marital + # countable and compare against (couple_fbr + N × $22) where N is + # the number of blind people in the unit. Split the supplement only + # when both spouses are blind (both route to BLIND); when only one + # spouse is blind, the non-blind spouse routes elsewhere and the + # blind spouse keeps the full per-blind allowance. + blind_count_in_unit = person.marital_unit.sum(is_blind) + blind_applicable_fbr = where(joint_claim, couple_fbr, individual_fbr) + blind_supplement_total = where( + joint_claim, blind_count_in_unit * p.blind, p.blind + ) + blind_compare_income = where(joint_claim, marital_countable, countable_monthly) blind_amt_full = max_( 0, (blind_applicable_fbr + blind_supplement_total) - max_(blind_compare_income, blind_applicable_fbr), ) - blind_amt = blind_amt_full / where(blind_couple, 2, 1) + joint_blind_couple = joint_claim & (blind_count_in_unit == 2) + blind_amt = blind_amt_full / where(joint_blind_couple, 2, 1) # DP — IAC 441—52.1(2): per-configuration assistance standard. Pick the # applicable Federal Benefit Rate (couple FBR for configurations that # include an eligible spouse, individual FBR otherwise) so the diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py index 862b6ae2517..99af99fc569 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_eligible.py @@ -13,6 +13,21 @@ class ia_ssa_eligible(Variable): ) def formula(person, period, parameters): - categorically_eligible = person("is_ssi_eligible", period.this_year) + # Use SSI's categorical eligibility (aged/blind/disabled + + # immigration) but apply Iowa's own resource test (IAC 441—51.5) + # rather than the federal SSI resource test. Federal applies the + # $2,000 individual limit when the spouse is not part of a joint + # SSI claim, which would block Iowa's $3,000 marital-unit limit + # for cases like a claimant with a non-ABD spouse and $2,500 in + # combined resources. IAC 441—51.1 lets Iowa SSA pay recipients + # who would qualify for SSI except for excess income, so the + # federal resource test should not gate Iowa eligibility. + abd = person("is_ssi_aged_blind_disabled", period.this_year) + is_qualified_noncitizen = person( + "is_ssi_qualified_noncitizen", period.this_year + ) + immigration_status = person("immigration_status", period.this_year) + is_citizen = immigration_status == immigration_status.possible_values.CITIZEN + meets_immigration = is_qualified_noncitizen | is_citizen resources_eligible = person("ia_ssa_resources_eligible", period) - return categorically_eligible & resources_eligible + return abd & meets_immigration & resources_eligible diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py index 404a5aa3e46..eb6636972d4 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py @@ -79,14 +79,15 @@ def formula(person, period, parameters): # supplement phases to zero when countable income reaches FBR + state # standard. Mirror that ceiling in the category gate so blind # recipients with excess income fall through to the next category. - # For joint SSI claims where both spouses are blind, - # ssi_countable_income returns combined / 2 per spouse, so aggregate - # marital countable and compare against (couple_fbr + 2 × $22). - blind_couple = joint_claim & (person.marital_unit.sum(is_blind) == 2) + # Any joint SSI claim uses couple-FBR basis: ssi_countable_income + # returns combined / 2 per spouse, so aggregate marital countable + # and compare against (couple_fbr + N × $22) where N is the number + # of blind people in the marital unit. + blind_count_in_unit = person.marital_unit.sum(is_blind) marital_countable = person.marital_unit.sum(countable_monthly) - blind_applicable_fbr = where(blind_couple, couple_fbr, individual_fbr) - blind_supplement = where(blind_couple, 2 * p.blind, p.blind) - blind_compare_income = where(blind_couple, marital_countable, countable_monthly) + blind_applicable_fbr = where(joint_claim, couple_fbr, individual_fbr) + blind_supplement = where(joint_claim, blind_count_in_unit * p.blind, p.blind) + blind_compare_income = where(joint_claim, marital_countable, countable_monthly) blind_income_eligible = ( blind_compare_income < blind_applicable_fbr + blind_supplement ) From 9da9a404c777ac9288a3d60e95b3ef8d2dec0a40 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 5 May 2026 02:28:12 -0400 Subject: [PATCH 22/23] Address /review-program critical findings on IA SSA - ia_ssa_living_arrangement: gate FLH and DP at the living-arrangement level by recipient/marital countable income vs the FLH standard (FBR + state_supplement) and the selected DP assistance standard, so high-income households fall through to SMME instead of being classified into a clamped-to-zero category. Use marital countable income for couple DP configurations to match the marital-unit-level standard. - ia_ssa_living_arrangement and ia_ssa: IHHRC home-maintenance disregard selects the couple SSI standard whenever a spouse lives in the home (per IAC 441-177.4(1)(f)(1) "as applicable" and Iowa HHS GL 6-B-46), not only when both spouses are SSI-categorically eligible. Renamed to ihhrc_basic_ssi_disregard to scope it to IHHRC; BLIND keeps joint_claim per IAC 441-52.1(4). - ia_ssa_resources_eligible: replace the IAC 441-51.5(2)-only citation with the broader umbrella authority (IAC 441-50.2) plus the federal SSI resource rules that govern non-DP arrangements (SSA POMS SI 01110.003, SI 01110.530, 20 CFR 416.1202(a)). Substantive policy unchanged: the $2k/$3k schedule applies whether the spouse is SSI-eligible or not, per federal SSI itself. --- .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 11 +++- .../ia/hhs/ssa/ia_ssa_living_arrangement.py | 54 ++++++++++++++++--- .../ia/hhs/ssa/ia_ssa_resources_eligible.py | 22 +++++--- 3 files changed, 72 insertions(+), 15 deletions(-) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py index aa021d7c611..ad5c7e2567c 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py @@ -144,9 +144,16 @@ def formula(person, period, parameters): # are not modeled. ihhrc_cost = person("ia_ssa_ihhrc_cost_of_care", period) both_need_care = person("ia_ssa_ihhrc_both_need_care", period) - basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) + # IAC 441—177.4(1)(f)(1) and Iowa HHS GL 6-B-46: deduct the basic SSI + # standard "for an individual or a couple, as applicable." The couple + # allowance applies whenever a spouse lives in the home, not only + # when both spouses are SSI-categorically eligible. + has_spouse_in_home = person.marital_unit.nb_persons() > 1 + ihhrc_basic_ssi_disregard = where( + has_spouse_in_home, couple_fbr, individual_fbr + ) combined_countable = person.marital_unit.sum(countable_no_disregard) - combined_participation = max_(0, combined_countable - basic_ssi_disregard) + combined_participation = max_(0, combined_countable - ihhrc_basic_ssi_disregard) ihhrc_client_participation = where( both_need_care, combined_participation / person.marital_unit.nb_persons(), diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py index eb6636972d4..3fe5c6d7493 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.py @@ -32,7 +32,16 @@ def formula(person, period, parameters): individual_fbr = p_ssi.individual couple_fbr = p_ssi.couple joint_claim = person("ssi_claim_is_joint", period.this_year) - basic_ssi_disregard = where(joint_claim, couple_fbr, individual_fbr) + marital_countable = person.marital_unit.sum(countable_monthly) + # IAC 441—177.4(1)(f)(1) and Iowa HHS GL 6-B-46: the IHHRC home + # maintenance allowance deducts the basic SSI standard "for an + # individual or a couple, as applicable." The couple allowance applies + # whenever a spouse lives in the home, not only when both spouses are + # SSI-categorically eligible. + has_spouse_in_home = person.marital_unit.nb_persons() > 1 + ihhrc_basic_ssi_disregard = where( + has_spouse_in_home, couple_fbr, individual_fbr + ) # IAC 441—51.4(3) cross-refs 52.1(3)"a": RCF income eligibility compares # client participation (total monthly income minus the personal needs # allowance) against 31 × the maximum per diem. GL 6-B-46 p. 54 omits @@ -54,19 +63,27 @@ def formula(person, period, parameters): # disregard, so use countable_no_disregard. combined_countable = person.marital_unit.sum(countable_no_disregard) ihhrc_countable_after_disregard = max_( - 0, combined_countable - basic_ssi_disregard + 0, combined_countable - ihhrc_basic_ssi_disregard ) ihhrc_cap = where( both_need_care, p.ihhrc.max_cost_couple, p.ihhrc.max_cost_single ) ihhrc_income_eligible = ihhrc_countable_after_disregard <= ihhrc_cap in_flh = arrangement_input == arr_input_values.FAMILY_LIFE_HOME + # IAC 441—50.2(1) and 52.1(1): the FLH supplement phases to zero when + # countable income reaches the FLH standard (FBR + state supplement). + # Gate at the living-arrangement level so FLH-living recipients with + # excess income fall through rather than blocking the SMME fallback. + flh_income_eligible = countable_monthly < ( + individual_fbr + p.flh.state_supplement + ) # IAC 441—177.4(1)(c): IHHRC recipients must live in their own home, # so exclude those residing in an RCF or family-life home. in_own_home = ~in_rcf & ~in_flh has_dependent = person("ia_ssa_dp_has_eligible_dependent", period) dp_configuration = person("ia_ssa_dp_configuration", period) - in_dp = dp_configuration != dp_configuration.possible_values.NONE + dp_config_values = dp_configuration.possible_values + in_dp = dp_configuration != dp_config_values.NONE # IAC 441—52.1(2): DP requires the dependent's countable income below # the dependent income limit (per IAC 441—51.5(1)). Gate at the # living-arrangement level so people who qualify for DP but fail the @@ -74,6 +91,28 @@ def formula(person, period, parameters): # receiving a zero DP supplement. dependent_income = person("ia_ssa_dp_dependent_countable_income", period) dependent_income_eligible = dependent_income < p.dp.dependent_income_limit + # IAC 441—50.2(1) and 52.1(2): the DP supplement phases to zero when + # the recipient/marital countable income reaches the configuration's + # assistance standard. Couple configurations describe the whole + # marital unit, so use marital countable income to match the + # marital-unit-level standard. + dp_assistance_standard = p.dp.assistance_standard[dp_configuration] + dp_has_spouse = ( + ( + dp_configuration + == dp_config_values.AGED_OR_DISABLED_WITH_SPOUSE_AND_DEPENDENT + ) + | ( + dp_configuration + == dp_config_values.BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT + ) + | ( + dp_configuration + == dp_config_values.BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT + ) + ) + dp_compare_income = where(dp_has_spouse, marital_countable, countable_monthly) + dp_recipient_income_eligible = dp_compare_income < dp_assistance_standard is_blind = person("is_blind", period.this_year) # IAC 441—52.1(4) blind standard is a federally-administered SSP; # supplement phases to zero when countable income reaches FBR + state @@ -84,7 +123,6 @@ def formula(person, period, parameters): # and compare against (couple_fbr + N × $22) where N is the number # of blind people in the marital unit. blind_count_in_unit = person.marital_unit.sum(is_blind) - marital_countable = person.marital_unit.sum(countable_monthly) blind_applicable_fbr = where(joint_claim, couple_fbr, individual_fbr) blind_supplement = where(joint_claim, blind_count_in_unit * p.blind, p.blind) blind_compare_income = where(joint_claim, marital_countable, countable_monthly) @@ -96,8 +134,12 @@ def formula(person, period, parameters): [ eligible & in_rcf & rcf_income_eligible, eligible & needs_ihhrc & in_own_home & ihhrc_income_eligible, - eligible & in_flh, - eligible & has_dependent & in_dp & dependent_income_eligible, + eligible & in_flh & flh_income_eligible, + eligible + & has_dependent + & in_dp + & dependent_income_eligible + & dp_recipient_income_eligible, eligible & is_blind & blind_income_eligible, eligible & smme_eligible, ], diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py index 339b2aae4e8..742db277ad9 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py @@ -8,16 +8,24 @@ class ia_ssa_resources_eligible(Variable): label = "Iowa SSA resources eligible" defined_for = StateCode.IA reference = ( - "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2" + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.50.pdf", + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf#page=2", + "https://secure.ssa.gov/poms.nsf/lnx/0501110003", + "https://secure.ssa.gov/poms.nsf/lnx/0501110530", + "https://www.ecfr.gov/current/title-20/chapter-III/part-416/subpart-K#p-416.1202(a)", ) def formula(person, period, parameters): - # IAC 441—51.5(2): the recipient resource limit is $2,000 alone or - # with a dependent child/parent only; $3,000 when there is a - # dependent spouse, or with a spouse and a dependent child/parent. - # Per 51.5(4) a dependent spouse can be an ineligible-but-financially- - # dependent spouse. Apply the $3,000 marital-unit limit whenever the - # recipient lives with any spouse — federal joint SSI claim is too + # IA SSA adopts the federal SSI $2,000 / $3,000 resource schedule + # under the umbrella authority of IAC 441—50.2 (resource policy + # follows SSI rules unless explicitly modified). Federal SSI applies + # the $3,000 limit to "an individual with a spouse" whether the + # spouse is eligible or ineligible, when they live in the same + # household: SSA POMS SI 01110.003 (limits) and SI 01110.530 (deeming + # of ineligible spouse resources), 20 CFR §416.1202(a). IAC + # 441—51.5(2) carries the same $2k/$3k schedule for the dependent- + # relative configuration. Apply the couple limit whenever the + # recipient lives with any spouse — using `ssi_claim_is_joint` is too # narrow because it requires both spouses to be SSI-categorically # eligible. individual_resources = person("ssi_countable_resources", period.this_year) From 4a12735448462422a831b3e2ba17bf63e97c9836 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 5 May 2026 02:37:55 -0400 Subject: [PATCH 23/23] Update IA SSA Case 10 to reflect new DP recipient-income gate DP and SMME income ranges are now disjoint by construction (DP requires countable < the configuration's assistance standard; SMME requires income > 120% FPL), so the original priority-test scenario can't exist. Reframe Case 10 to assert the new fall-through behavior: a DP-configured person whose income exceeds the DP standard falls through to SMME. --- .../states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml index 84757ed8002..2b03369d7dd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_living_arrangement.yaml @@ -226,14 +226,14 @@ # priority ordering between them is academic. ia_ssa_living_arrangement: [SMME] -- name: Case 10, DP-configured person with SMME-eligible income gets DP not SMME. +- name: Case 10, DP-configured person with over-DP-standard income falls through to SMME. period: 2025-01 absolute_error_margin: 0.01 input: people: person1: age: 70 - social_security_retirement: 24_000 + social_security_retirement: 24_000 # $2,000/mo -> countable $1,980 ia_ssa_dp_configuration: AGED_OR_DISABLED_WITH_DEPENDENT ia_ssa_dp_has_eligible_dependent: true ia_ssa_has_full_medicaid: true @@ -252,8 +252,12 @@ members: [person1] state_code: IA output: - # DP outranks SMME - ia_ssa_living_arrangement: [DP] + # The 2025 AGED_OR_DISABLED_WITH_DEPENDENT DP standard is $1,470. Countable + # $1,980 > $1,470, so the DP recipient-income gate fails and the person + # falls through to SMME (income > 120% FPL of $1,565). DP and SMME income + # ranges are disjoint by construction — the priority cascade between them + # is academic. + ia_ssa_living_arrangement: [SMME] - name: Case 11, IHHRC person with SMME-eligible income gets IHHRC not SMME. period: 2025-01