From 7c38911c55712275a07cff80c2699444bd454f98 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 16 Apr 2026 12:59:17 -0400 Subject: [PATCH 01/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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/33] 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 From acf387bb0b32c86f7a8d8b29e904c64832888ea6 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 13 Oct 2026 00:58:18 -0400 Subject: [PATCH 24/33] Normalize Iowa SSP parameter and test formatting --- .../household/household_state_benefits.yaml | 1 + .../hud/annual_income/sources/unearned.yaml | 1 + .../exclusions/child_support_share.yaml | 10 +- .../ssi/state_supplement/minimum_payment.yaml | 1 + .../gov/states/ia/hhs/ssa/blind_amount.yaml | 13 +- .../states/ia/hhs/ssa/dependent_amount.yaml | 13 +- .../ia/hhs/ssa/family_life_couple_amount.yaml | 13 +- .../ssa/family_life_individual_amount.yaml | 13 +- .../states/ia/hhs/ssa/family_life_need.yaml | 9 +- .../states/ia/hhs/ssa/ihhrc_cost_limit.yaml | 9 +- .../states/ia/hhs/ssa/rcf_daily_limit.yaml | 7 +- .../states/ia/hhs/ssa/rcf_personal_needs.yaml | 9 +- .../gov/states/ia/hhs/ssa/smme_amount.yaml | 9 +- .../ia/hhs/ssa/smme_minimum_fpg_rate.yaml | 7 +- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 749 ++++++++---------- .../ia_ssa_resources_deemed_from_parents.yaml | 401 ++++------ .../gov/states/ia/hhs/ssa/integration.yaml | 142 ++-- 17 files changed, 600 insertions(+), 807 deletions(-) diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index 2aa2cc95991..a97138c61e0 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -405,6 +405,7 @@ values: - nj_property_tax_relief # New York benefits - ny_child_care_subsidies + metadata: unit: list period: year diff --git a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml index 1b7b46e8216..efa833c5cc7 100644 --- a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml @@ -30,6 +30,7 @@ values: - disability_benefits - survivor_benefits - financial_assistance + metadata: unit: list period: year diff --git a/policyengine_us/parameters/gov/ssa/ssi/income/exclusions/child_support_share.yaml b/policyengine_us/parameters/gov/ssa/ssi/income/exclusions/child_support_share.yaml index a5f0fdb42a5..81c360b8302 100644 --- a/policyengine_us/parameters/gov/ssa/ssi/income/exclusions/child_support_share.yaml +++ b/policyengine_us/parameters/gov/ssa/ssi/income/exclusions/child_support_share.yaml @@ -1,10 +1,10 @@ -description: The Social Security Administration excludes this share of child support received - by an eligible child from SSI unearned income. +description: The Social Security Administration excludes this share of child support received by an eligible child from SSI unearned income. values: - '2026-01-01': 0.3333333333333333 + 2026-01-01: 0.3333333333333333 + metadata: unit: /1 label: SSI child support exclusion share reference: - - title: 20 CFR 416.1124(c)(11) - href: https://www.law.cornell.edu/cfr/text/20/416.1124 + - title: 20 CFR 416.1124(c)(11) + href: https://www.law.cornell.edu/cfr/text/20/416.1124 diff --git a/policyengine_us/parameters/gov/ssa/ssi/state_supplement/minimum_payment.yaml b/policyengine_us/parameters/gov/ssa/ssi/state_supplement/minimum_payment.yaml index 96464c8c040..1d3e6e2e6b6 100644 --- a/policyengine_us/parameters/gov/ssa/ssi/state_supplement/minimum_payment.yaml +++ b/policyengine_us/parameters/gov/ssa/ssi/state_supplement/minimum_payment.yaml @@ -1,6 +1,7 @@ description: The Social Security Administration pays at least this monthly amount to each recipient of a positive federally administered optional state supplement. values: 2026-01-01: 1 + metadata: unit: currency-USD period: month diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind_amount.yaml index dc754697d24..15f5c221f54 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind_amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind_amount.yaml @@ -1,12 +1,13 @@ description: Iowa uses this amount as its blind supplement. values: - '2026-01-01': 22 + 2026-01-01: 22 + metadata: unit: currency-USD + period: month label: Iowa SSA blind supplement reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - - title: SSA 2026 federally administered supplements, Iowa - href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f - period: month + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= + - title: SSA 2026 federally administered supplements, Iowa + href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml index 1a3d490b15e..50892f56394 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml @@ -1,12 +1,13 @@ description: Iowa uses this amount as its dependent-person supplement. values: - '2026-01-01': 518 + 2026-01-01: 518 + metadata: unit: currency-USD + period: month label: Iowa SSA dependent-person supplement reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - - title: SSA 2026 federally administered supplements, Iowa - href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f - period: month + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= + - title: SSA 2026 federally administered supplements, Iowa + href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_couple_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_couple_amount.yaml index 5474ec681a1..9c2f78728b8 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_couple_amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_couple_amount.yaml @@ -1,12 +1,13 @@ description: Iowa uses this amount as its couple federally administered family-life supplement. values: - '2026-01-01': 801 + 2026-01-01: 801 + metadata: unit: currency-USD + period: month label: Iowa SSA couple federally administered family-life supplement reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - - title: SSA 2026 federally administered supplements, Iowa - href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f - period: month + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= + - title: SSA 2026 federally administered supplements, Iowa + href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_individual_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_individual_amount.yaml index 1ffbb307e56..9c66a8e9636 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_individual_amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_individual_amount.yaml @@ -1,12 +1,13 @@ description: Iowa uses this amount as its individual federally administered family-life supplement. values: - '2026-01-01': 142 + 2026-01-01: 142 + metadata: unit: currency-USD + period: month label: Iowa SSA individual federally administered family-life supplement reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - - title: SSA 2026 federally administered supplements, Iowa - href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f - period: month + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= + - title: SSA 2026 federally administered supplements, Iowa + href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_need.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_need.yaml index fb12663adf3..e946cde2ab0 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_need.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_need.yaml @@ -1,10 +1,11 @@ description: Iowa uses this amount as its family-life home need standard. values: - '2026-01-01': 1156 + 2026-01-01: 1_156 + metadata: unit: currency-USD + period: month label: Iowa SSA family-life home need standard reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - period: month + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml index 3ab208bdf0f..186891d8424 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml @@ -1,10 +1,11 @@ description: Iowa uses this amount as its maximum in-home care monthly cost per recipient. values: - '2026-01-01': 480.55 + 2026-01-01: 480.55 + metadata: unit: currency-USD + period: month label: Iowa SSA maximum in-home care monthly cost per recipient reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - period: month + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml index 6ba054b23b1..2075e98afe6 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml @@ -1,9 +1,10 @@ description: Iowa uses this amount as its maximum residential care daily rate. values: - '2026-01-01': 38.47 + 2026-01-01: 38.47 + metadata: unit: currency-USD label: Iowa SSA maximum residential care daily rate reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml index 5dba51e3f1b..bfd749596c7 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml @@ -1,10 +1,11 @@ description: Iowa uses this amount as its residential care personal needs allowance. values: - '2026-01-01': 130 + 2026-01-01: 130 + metadata: unit: currency-USD + period: month label: Iowa SSA residential care personal needs allowance reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - period: month + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= 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 50ca681d8fc..a353885282d 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,10 +1,11 @@ description: Iowa uses this amount as its monthly Medicare and Medicaid supplement. values: - '2026-01-01': 1 + 2026-01-01: 1 + metadata: unit: currency-USD + period: month label: Iowa SSA monthly Medicare and Medicaid supplement reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - period: month + - title: Iowa HHS Employees Manual 6-B, 2026 + href: https://hhs.iowa.gov/media/3987/download?inline= diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml index c5fbbe9a9bd..700a09d03b2 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml @@ -1,9 +1,10 @@ description: Iowa requires SMME countable income to exceed this share of the federal poverty guideline. values: - '2026-01-01': 1.2 + 2026-01-01: 1.2 + metadata: unit: /1 label: Iowa SMME minimum income FPG rate reference: - - title: Iowa HHS Employees Manual 6-B, SMME income - href: https://hhs.iowa.gov/media/3987/download?inline= + - title: Iowa HHS Employees Manual 6-B, SMME income + href: https://hhs.iowa.gov/media/3987/download?inline= 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 2f0e22f5663..13681678d0c 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 @@ -3,425 +3,459 @@ absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 output: ia_ssa: 0 + - name: Case 2, ordinary blind supplement. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 is_blind: true output: ia_ssa: 22 + - name: Case 3, blind state-only income gap. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 is_blind: true - social_security_retirement: 12240 + social_security_retirement: 12_240 output: ia_ssa: 16 + - name: Case 4, dependent-person supplement. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: DEPENDENT_PERSON output: ia_ssa: 518 + - name: Case 5, blind dependent-person recipient. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: DEPENDENT_PERSON is_blind: true output: ia_ssa: 540 + - name: Case 6, dependent income at limit. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: DEPENDENT_PERSON ia_ssa_dependent_countable_income: 518 output: ia_ssa: 0 + - name: Case 7, dependent income is an eligibility gate not a grant deduction. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: DEPENDENT_PERSON ia_ssa_dependent_countable_income: 100 output: ia_ssa: 518 + - name: Case 8, total dependent group income exceeds standard. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: DEPENDENT_PERSON - social_security_retirement: 18000 + social_security_retirement: 18_000 ia_ssa_dependent_countable_income: 40 output: ia_ssa: 0 + - name: Case 9, family life home SSI-only top up. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: FAMILY_LIFE_HOME output: ia_ssa: 162 + - name: Case 10, blind family-life home stacks blind supplement. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: FAMILY_LIFE_HOME is_blind: true output: ia_ssa: 184 + - name: Case 11, family-life home with other unearned income. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: FAMILY_LIFE_HOME - social_security_retirement: 1200 + social_security_retirement: 1_200 output: ia_ssa: 142 + - name: Case 12, family-life home earnings do not qualify for SSI-only top up. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: FAMILY_LIFE_HOME - employment_income: 1200 + employment_income: 1_200 output: ia_ssa: 142 + - name: Case 13, state-only family-life payment. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: FAMILY_LIFE_HOME - social_security_retirement: 13200 + social_security_retirement: 13_200 output: ia_ssa: 56 + - name: Case 14, RCF actual January cost less participation. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 38.47 output: ia_ssa: 328.57 + - name: Case 15, RCF February uses actual days not eligibility multiplier. period: 2026-02 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 38.47 output: ia_ssa: 213.16 + - name: Case 16, blind RCF resident also gets blind supplement. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 38.47 is_blind: true output: ia_ssa: 350.57 + - name: Case 17, RCF no general income disregard. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 38.47 - social_security_retirement: 6516 + social_security_retirement: 6_516 output: ia_ssa: 308.57 + - name: Case 18, RCF verified medical and family deductions. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 38.47 ia_ssa_care_additional_deductions: 50 output: ia_ssa: 378.57 + - name: Case 19, RCF approved daily rate is capped. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 100 output: ia_ssa: 328.57 + - name: Case 20, RCF requires a facility rate. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: RESIDENTIAL_CARE output: ia_ssa: 0 + - name: Case 21, in-home care at approved cost. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 output: ia_ssa: 400 + - name: Case 22, in-home care cost at ceiling. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 480.55 output: ia_ssa: 480.55 + - name: Case 23, in-home cost over ceiling makes care ineligible. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 480.56 output: ia_ssa: 0 + - name: Case 24, manual IHHRC example with social security and SSI. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 - social_security_retirement: 6516 + social_security_retirement: 6_516 output: ia_ssa: 380 + - name: Case 25, IHHRC medical deductions reduce participation. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 - social_security_retirement: 16800 + social_security_retirement: 16_800 ia_ssa_care_additional_deductions: 100 output: ia_ssa: 94 + - name: Case 26, first partial in-home month has no participation. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 - social_security_retirement: 16800 + social_security_retirement: 16_800 ia_ssa_care_days: 16 ia_ssa_ihhrc_initial_partial_month: true output: ia_ssa: 206.4516129032258 + - name: Case 27, blind allowance coexists with in-home care. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_blind: true output: ia_ssa: 422 + - name: Case 28, excess resources. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 is_blind: true - ssi_countable_resources: 2001 + ssi_countable_resources: 2_001 output: ia_ssa: 0 + - name: Case 29, nonresident. period: 2026-01 absolute_error_margin: 0.01 input: state_code: NE age: - '2026': 65 + 2026: 65 is_blind: true output: ia_ssa: 0 + - name: Case 30, opt out. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 is_blind: true takes_up_ssi_if_eligible: false output: ia_ssa: 0 + - name: Case 31, medical facility has no ordinary blind supplement. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 is_blind: true ssi_federal_living_arrangement: MEDICAL_TREATMENT_FACILITY output: ia_ssa: 0 + - name: Case 32, SMME requires full Medicaid and Part B. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: SMME ia_ssa_smme_coverage_eligible: true - ia_ssa_smme_countable_income: 2000 + ia_ssa_smme_countable_income: 2_000 output: ia_ssa: 1 + - name: Case 33, SMME missing coverage. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: SMME - ia_ssa_smme_countable_income: 2000 + ia_ssa_smme_countable_income: 2_000 output: ia_ssa: 0 + - name: Case 34, SMME income below 120 percent poverty. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: SMME ia_ssa_smme_coverage_eligible: true - ia_ssa_smme_countable_income: 1000 + ia_ssa_smme_countable_income: 1_000 output: ia_ssa: 0 + - name: Case 35, SMME cannot stack with blind payment. period: 2026-01 absolute_error_margin: 0.01 input: state_code: - '2026': IA + 2026: IA age: - '2026': 65 + 2026: 65 ia_ssa_category: SMME ia_ssa_smme_coverage_eligible: true - ia_ssa_smme_countable_income: 2000 + ia_ssa_smme_countable_income: 2_000 is_blind: true output: ia_ssa: 22 @@ -434,587 +468,468 @@ absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 10000 - child1: + 2026: 10_000 + person2: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 + members: [person2] + families: + family: + members: [person1, person2] tax_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 - families: - family: - members: - - parent1 - - child1 + members: [person2] spm_units: unit: - members: - - parent1 - - child1 + members: [person1, person2] households: home: - members: - - parent1 - - child1 + members: [person1, person2] state_code: - '2026': IA + 2026: IA output: - ia_ssa: - - 0 - - 0 + ia_ssa: [0, 0] + - name: Case 37, one-parent allowance and child ceiling are inclusive. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 4000 - child1: + 2026: 4_000 + person2: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 + members: [person2] + families: + family: + members: [person1, person2] tax_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 - families: - family: - members: - - parent1 - - child1 + members: [person2] spm_units: unit: - members: - - parent1 - - child1 + members: [person1, person2] households: home: - members: - - parent1 - - child1 + members: [person1, person2] state_code: - '2026': IA + 2026: IA output: - ia_ssa: - - 0 - - 400 + ia_ssa: [0, 400] + - name: Case 38, one cent above the combined allowances defeats eligibility. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 4000.01 - child1: + 2026: 4_000.01 + person2: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 + members: [person2] + families: + family: + members: [person1, person2] tax_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 - families: - family: - members: - - parent1 - - child1 + members: [person2] spm_units: unit: - members: - - parent1 - - child1 + members: [person1, person2] households: home: - members: - - parent1 - - child1 + members: [person1, person2] state_code: - '2026': IA + 2026: IA output: - ia_ssa: - - 0 - - 0 + ia_ssa: [0, 0] + - name: Case 39, an adult child does not receive deemed parental resources. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 10000 - child1: + 2026: 10_000 + person2: age: - '2026': 19 + 2026: 19 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 + members: [person2] + families: + family: + members: [person1, person2] tax_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 - families: - family: - members: - - parent1 - - child1 + members: [person2] spm_units: unit: - members: - - parent1 - - child1 + members: [person1, person2] households: home: - members: - - parent1 - - child1 + members: [person1, person2] state_code: - '2026': IA + 2026: IA output: - ia_ssa: - - 0 - - 400 + ia_ssa: [0, 400] + - name: Case 40, co-residence alone does not deem an unrelated adult resource balance. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 0 - child1: + 2026: 0 + person2: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true - unrelated: + 2026: true + person3: age: - '2026': 40 + 2026: 40 person_id: - '2026': 4 + 2026: 4 bank_account_assets: - '2026': 10000 + 2026: 10_000 marital_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 + members: [person2] unrelated: - members: - - unrelated + members: [person3] + families: + family: + members: [person1, person2, person3] tax_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 + members: [person2] unrelated: - members: - - unrelated - families: - family: - members: - - parent1 - - child1 - - unrelated + members: [person3] spm_units: unit: - members: - - parent1 - - child1 - - unrelated + members: [person1, person2, person3] households: home: - members: - - parent1 - - child1 - - unrelated + members: [person1, person2, person3] state_code: - '2026': IA + 2026: IA output: - ia_ssa: - - 0 - - 400 - - 0 + ia_ssa: [0, 400, 0] + - name: Case 41, two eligible siblings share the same two-parent excess. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 5500 - parent2: + 2026: 5_500 + person2: age: - '2026': 40 + 2026: 40 person_id: - '2026': 2 - child1: + 2026: 2 + person3: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true - child2: + 2026: true + person4: age: - '2026': 10 + 2026: 10 person_id: - '2026': 4 + 2026: 4 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 bank_account_assets: - '2026': 0 + 2026: 0 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 + members: [person4] + families: + family: + members: [person1, person2, person3, person4] tax_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 - families: - family: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person4] spm_units: unit: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person1, person2, person3, person4] households: home: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person1, person2, person3, person4] state_code: - '2026': IA + 2026: IA output: - ia_ssa: - - 0 - - 0 - - 400 - - 400 + ia_ssa: [0, 0, 400, 400] + - name: Case 42, an own-resource failure removes that sibling and reallocates the excess. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 5500 - parent2: + 2026: 5_500 + person2: age: - '2026': 40 + 2026: 40 person_id: - '2026': 2 - child1: + 2026: 2 + person3: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true - child2: + 2026: true + person4: age: - '2026': 10 + 2026: 10 person_id: - '2026': 4 + 2026: 4 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 bank_account_assets: - '2026': 1500 + 2026: 1_500 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 + members: [person4] + families: + family: + members: [person1, person2, person3, person4] tax_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 - families: - family: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person4] spm_units: unit: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person1, person2, person3, person4] households: home: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person1, person2, person3, person4] state_code: - '2026': IA + 2026: IA output: - ia_ssa: - - 0 - - 0 - - 0 - - 0 + ia_ssa: [0, 0, 0, 0] + - name: Case 43, a linked parent outside the household is not a resource deemor. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 10000 - child1: + 2026: 10_000 + person2: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 + members: [person2] + families: + family: + members: [person1, person2] tax_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 - families: - family: - members: - - parent1 - - child1 + members: [person2] spm_units: unit: - members: - - parent1 - - child1 + members: [person1, person2] households: parent_home: - members: - - parent1 + members: [person1] state_code: - '2026': IA + 2026: IA child_home: - members: - - child1 + members: [person2] state_code: - '2026': IA + 2026: IA output: - ia_ssa: - - 0 - - 400 + ia_ssa: [0, 400] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml index f9ec56522cb..4106fb08f26 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml @@ -1,415 +1,314 @@ # Resource balances and certified budgets are stocks. Annual demographic and asset inputs are explicit. -- name: Annual asset balances remain undivided in January and July +- name: Case 1, Annual asset balances remain undivided in January and July. period: 2026 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 10000 - child1: + 2026: 10_000 + person2: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 2026-01: 400 2026-07: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 + members: [person2] + families: + family: + members: [person1, person2] tax_units: parent1: - members: - - parent1 + members: [person1] child1: - members: - - child1 - families: - family: - members: - - parent1 - - child1 + members: [person2] spm_units: unit: - members: - - parent1 - - child1 + members: [person1, person2] households: home: - members: - - parent1 - - child1 + members: [person1, person2] state_code: - '2026': IA + 2026: IA output: ia_ssa_resources_deemed_from_parents: - 2026-01: - - 0 - - 8000 - 2026-07: - - 0 - - 8000 -- name: Annual agency-certified resource budget remains a monthly stock + 2026-01: [0, 8_000] + 2026-07: [0, 8_000] + +- name: Case 2, Annual agency-certified resource budget remains a monthly stock. period: 2026 absolute_error_margin: 0.01 input: state_code: IA - ia_ssa_resources_deemed_from_parents: 2500 + ia_ssa_resources_deemed_from_parents: 2_500 output: ia_ssa_resources_deemed_from_parents: - 2026-01: 2500 - 2026-07: 2500 -- name: Minor household head is excluded from parental deeming and the sibling allocation - pool + 2026-01: 2_500 + 2026-07: 2_500 + +- name: Case 3, Minor household head is excluded from parental deeming and the sibling allocation pool. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 5500 - parent2: + 2026: 5_500 + person2: age: - '2026': 40 + 2026: 40 person_id: - '2026': 2 - child1: + 2026: 2 + person3: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_household_head: - '2026': true + 2026: true is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true - child2: + 2026: true + person4: age: - '2026': 10 + 2026: 10 person_id: - '2026': 4 + 2026: 4 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 + members: [person4] + families: + family: + members: [person1, person2, person3, person4] tax_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 - families: - family: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person4] spm_units: unit: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person1, person2, person3, person4] households: home: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person1, person2, person3, person4] state_code: - '2026': IA + 2026: IA output: - ia_ssa_resources_deemed_from_parents: - - 0 - - 0 - - 0 - - 2500 - ia_ssa: - - 0 - - 0 - - 400 - - 0 -- name: Married minor is excluded from parental deeming and the sibling allocation pool + ia_ssa_resources_deemed_from_parents: [0, 0, 0, 2_500] + ia_ssa: [0, 0, 400, 0] + +- name: Case 4, Married minor is excluded from parental deeming and the sibling allocation pool. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 5500 - parent2: + 2026: 5_500 + person2: age: - '2026': 40 + 2026: 40 person_id: - '2026': 2 - child1: + 2026: 2 + person3: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true - child2: + 2026: true + person4: age: - '2026': 10 + 2026: 10 person_id: - '2026': 4 + 2026: 4 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true - spouse: + 2026: true + person5: age: - '2026': 17 + 2026: 17 person_id: - '2026': 5 + 2026: 5 marital_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 - - spouse + members: [person3, person5] child2: - members: - - child2 + members: [person4] + families: + family: + members: [person1, person2, person3, person4, person5] tax_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 + members: [person4] spouse: - members: - - spouse - families: - family: - members: - - parent1 - - parent2 - - child1 - - child2 - - spouse + members: [person5] spm_units: unit: - members: - - parent1 - - parent2 - - child1 - - child2 - - spouse + members: [person1, person2, person3, person4, person5] households: home: - members: - - parent1 - - parent2 - - child1 - - child2 - - spouse + members: [person1, person2, person3, person4, person5] state_code: - '2026': IA + 2026: IA output: - ia_ssa_resources_deemed_from_parents: - - 0 - - 0 - - 0 - - 2500 - - 0 - ia_ssa: - - 0 - - 0 - - 400 - - 0 - - 0 + ia_ssa_resources_deemed_from_parents: [0, 0, 0, 2_500, 0] + ia_ssa: [0, 0, 400, 0, 0 # Child-specific parental budgets and sibling allocation: SI 01330.200/.280. -- name: Children with different linked parent sets do not share a resource allocation +] + +- name: Case 5, Children with different linked parent sets do not share a resource allocation. period: 2026-06 absolute_error_margin: 0.01 input: people: - parent1: + person1: age: - '2026': 40 + 2026: 40 person_id: - '2026': 1 + 2026: 1 bank_account_assets: - '2026': 5500 - parent2: + 2026: 5_500 + person2: age: - '2026': 40 + 2026: 40 person_id: - '2026': 2 - child1: + 2026: 2 + person3: age: - '2026': 10 + 2026: 10 person_id: - '2026': 3 + 2026: 3 parent_1_id: - '2026': 1 + 2026: 1 parent_2_id: - '2026': 2 + 2026: 2 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true - child2: + 2026: true + person4: age: - '2026': 10 + 2026: 10 person_id: - '2026': 4 + 2026: 4 parent_1_id: - '2026': 1 + 2026: 1 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 is_disabled: - '2026': true + 2026: true meets_ssi_disability_criteria: - '2026': true + 2026: true marital_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 + members: [person4] + families: + family: + members: [person1, person2, person3, person4] tax_units: parent1: - members: - - parent1 + members: [person1] parent2: - members: - - parent2 + members: [person2] child1: - members: - - child1 + members: [person3] child2: - members: - - child2 - families: - family: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person4] spm_units: unit: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person1, person2, person3, person4] households: home: - members: - - parent1 - - parent2 - - child1 - - child2 + members: [person1, person2, person3, person4] state_code: - '2026': IA + 2026: IA output: - ia_ssa_resources_deemed_from_parents: - - 0 - - 0 - - 2500 - - 3500 - ia_ssa: - - 0 - - 0 - - 0 - - 0 + ia_ssa_resources_deemed_from_parents: [0, 0, 2_500, 3_500] + ia_ssa: [0, 0, 0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml index d0765685034..dbde9194455 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml @@ -3,190 +3,155 @@ absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 is_blind: true - second: + person2: age: 65 marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: IA output: - ia_ssa: - - 22 - - 0 + ia_ssa: [22, 0] + - name: Case 2, two blind spouses. period: 2026-01 absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 is_blind: true - second: + person2: age: 65 is_blind: true marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: IA output: - ia_ssa: - - 22 - - 22 + ia_ssa: [22, 22] + - name: Case 3, dependent-person grant is once per eligible couple. period: 2026-01 absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 ia_ssa_category: DEPENDENT_PERSON - second: + person2: age: 65 ia_ssa_category: DEPENDENT_PERSON marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: IA output: - ia_ssa: - - 259 - - 259 + ia_ssa: [259, 259] + - name: Case 4, mixed blind dependent-person couple follows state manual. period: 2026-01 absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 ia_ssa_category: DEPENDENT_PERSON is_blind: true - second: + person2: age: 65 ia_ssa_category: DEPENDENT_PERSON marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: IA output: - ia_ssa: - - 270 - - 270 + ia_ssa: [270, 270] + - name: Case 5, family-life home eligible couple. period: 2026-01 absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 ia_ssa_category: FAMILY_LIFE_HOME - second: + person2: age: 65 ia_ssa_category: FAMILY_LIFE_HOME marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: IA output: - ia_ssa: - - 410.5 - - 410.5 + ia_ssa: [410.5, 410.5] + - name: Case 6, in-home care counts ineligible spouse income. period: 2026-01 absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 - second: + person2: age: 40 - social_security_retirement: 20400 + social_security_retirement: 20_400 marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: IA output: - ia_ssa: - - 191 - - 0 + ia_ssa: [191, 0] + - name: Case 7, in-home couple gets only one earnings disregard. period: 2026-01 absolute_error_margin: 0.01 input: people: - first: + person1: age: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 - employment_income: 24000 - second: + employment_income: 24_000 + person2: age: 65 ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 - employment_income: 12000 + employment_income: 12_000 marital_units: couple: - members: - - first - - second + members: [person1, person2] households: hh: - members: - - first - - second + members: [person1, person2] state_code: IA output: - ia_ssa: - - 395 - - 395 + ia_ssa: [395, 395] + - name: Case 8, annual blind allowance and SNAP income. - period: '2026' + period: 2026 absolute_error_margin: 0.01 input: age: 65 @@ -194,17 +159,18 @@ is_blind: true output: ia_ssa: 264 - snap_unearned_income: 12192 -- name: Iowa in-home reimbursement is excluded while blind cash is counted - period: '2026' + snap_unearned_income: 12_192 + +- name: Case 9, Iowa in-home reimbursement is excluded while blind cash is counted. + period: 2026 absolute_error_margin: 0.01 input: state_code: IA age: 65 is_blind: true ia_ssa_category: IN_HOME_CARE - ia_ssa_ihhrc_monthly_cost: 4800 + ia_ssa_ihhrc_monthly_cost: 4_800 output: - ia_ssa: 5064 - snap_unearned_income: 12192 - hud_unearned_income: 12192 + ia_ssa: 5_064 + snap_unearned_income: 12_192 + hud_unearned_income: 12_192 From eb4e86a0433af03fa2a4d77547520a26f6674b0d Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 20 Oct 2026 05:04:28 -0400 Subject: [PATCH 25/33] Address review findings on Iowa State Supplementary Assistance Replace builtin sum() and formula-variable overrides with plain zero-default inputs and default formulas, reuse main's parental resource pool (stepparent gap), let over-income residential care, in-home care and SMME applicants pursue the state payment, derive FBR-linked standards, fix shared-list wiring and the registry entry, add NOTEs for the source conflicts, and extend coverage. Co-Authored-By: Claude Opus 5.5 --- .../household/household_state_benefits.yaml | 12 +- .../hud/annual_income/sources/unearned.yaml | 4 +- .../gov/states/ia/hhs/ssa/blind_amount.yaml | 12 +- .../states/ia/hhs/ssa/dependent_amount.yaml | 16 +- .../ia/hhs/ssa/family_life_couple_amount.yaml | 13 - .../ssa/family_life_individual_amount.yaml | 13 - .../states/ia/hhs/ssa/family_life_need.yaml | 11 - .../ia/hhs/ssa/family_life_supplement.yaml | 19 + .../states/ia/hhs/ssa/ihhrc_cost_limit.yaml | 19 +- .../states/ia/hhs/ssa/rcf_daily_limit.yaml | 12 +- .../states/ia/hhs/ssa/rcf_personal_needs.yaml | 11 +- .../gov/states/ia/hhs/ssa/smme_amount.yaml | 10 +- .../ia/hhs/ssa/smme_minimum_fpg_rate.yaml | 9 +- .../usda/snap/income/sources/unearned.yaml | 10 +- policyengine_us/programs.yaml | 16 +- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 358 +++++++++++++++++- .../ia_ssa_income_deemed_from_parents.yaml | 310 +++++++++++++++ .../hhs/ssa/ia_ssa_nonfinancial_eligible.yaml | 75 ++++ .../ia_ssa_resources_deemed_from_parents.yaml | 114 +++++- .../gov/states/ia/hhs/ssa/integration.yaml | 39 +- .../gov/states/_ssp_parental_resources.py | 76 ---- .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 69 ++-- .../ssa/ia_ssa_care_additional_deductions.py | 14 +- .../hhs/ssa/ia_ssa_care_countable_income.py | 22 +- .../gov/states/ia/hhs/ssa/ia_ssa_care_days.py | 13 - .../hhs/ssa/ia_ssa_care_partial_month_days.py | 21 + .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 3 +- .../ia/hhs/ssa/ia_ssa_countable_for_hud.py | 25 ++ .../ia/hhs/ssa/ia_ssa_countable_for_snap.py | 12 +- .../ssa/ia_ssa_dependent_countable_income.py | 5 +- .../gov/states/ia/hhs/ssa/ia_ssa_eligible.py | 28 +- .../gov/states/ia/hhs/ssa/ia_ssa_federal.py | 43 ++- .../states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py | 38 ++ .../ssa/ia_ssa_ihhrc_initial_partial_month.py | 13 +- .../ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py | 4 +- .../ia/hhs/ssa/ia_ssa_ihhrc_participation.py | 35 ++ .../ssa/ia_ssa_income_deemed_from_parents.py | 88 +++++ .../hhs/ssa/ia_ssa_nonfinancial_eligible.py | 39 ++ .../ia/hhs/ssa/ia_ssa_rcf_daily_rate.py | 3 +- .../ia_ssa_resources_deemed_from_parents.py | 93 ++--- .../hhs/ssa/ia_ssa_smme_countable_income.py | 5 +- .../hhs/ssa/ia_ssa_smme_coverage_eligible.py | 2 +- .../income/spm_unit/spm_unit_benefits.py | 2 +- 43 files changed, 1434 insertions(+), 302 deletions(-) delete mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_couple_amount.yaml delete mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_individual_amount.yaml delete mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_need.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_supplement.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.yaml delete mode 100644 policyengine_us/variables/gov/states/_ssp_parental_resources.py delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_days.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_partial_month_days.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_for_hud.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index 92c4a8974b9..cb46b0d5c17 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -86,8 +86,9 @@ values: - ma_eaedc # DC benefits - dc_ossp - # Kansas benefits + # Iowa benefits - ia_ssa + # Kansas benefits - ks_sspp # Hawaii benefits - hi_oss @@ -193,8 +194,9 @@ values: - ma_eaedc # DC benefits - dc_ossp - # Kansas benefits + # Iowa benefits - ia_ssa + # Kansas benefits - ks_sspp # Hawaii benefits - hi_oss @@ -305,8 +307,9 @@ values: # DC benefits - dc_ossp - dc_child_care_subsidies - # Kansas benefits + # Iowa benefits - ia_ssa + # Kansas benefits - ks_sspp # Hawaii benefits - hi_oss @@ -417,8 +420,9 @@ values: # DC benefits - dc_ossp - dc_child_care_subsidies - # Kansas benefits + # Iowa benefits - ia_ssa + # Kansas benefits - ks_sspp # Hawaii benefits - hi_oss diff --git a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml index a30b7008970..59655306f60 100644 --- a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml @@ -24,7 +24,7 @@ values: - wy_ssp - nc_sa_countable_for_hud - nv_oss - - ia_ssa_countable_for_snap + - ia_ssa_countable_for_hud - general_assistance - total_unemployment_compensation - child_support_received @@ -41,5 +41,5 @@ metadata: period: year label: HUD unearned income sources reference: - - title: 24 CFR § 5.609(a)(1), (a)(2), (b)(6), (b)(19) + - title: 24 CFR § 5.609(a)(1), (a)(2) href: https://www.law.cornell.edu/cfr/text/24/5.609 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind_amount.yaml index 15f5c221f54..16e62203137 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind_amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/blind_amount.yaml @@ -1,4 +1,4 @@ -description: Iowa uses this amount as its blind supplement. +description: Iowa provides this amount as the monthly blind supplement under the State Supplementary Assistance program. values: 2026-01-01: 22 @@ -7,7 +7,9 @@ metadata: period: month label: Iowa SSA blind supplement reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - - title: SSA 2026 federally administered supplements, Iowa - href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f + - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Blind Supplement + href: https://hhs.iowa.gov/media/3987/download?inline=#page=20 + - title: 441 IAC 52.1(4) + href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=2 + - title: SSA POMS SI 01415.058 F.2.a (TN 95, 08-26), Iowa recipient payment levels + href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f2a diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml index 50892f56394..1c32d33aae0 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml @@ -1,4 +1,4 @@ -description: Iowa uses this amount as its dependent-person supplement. +description: Iowa provides this amount as the monthly dependent-person supplement under the State Supplementary Assistance program. values: 2026-01-01: 518 @@ -6,8 +6,14 @@ metadata: unit: currency-USD period: month label: Iowa SSA dependent-person supplement + # The same amount is the dependent's income limit (6-B Nonfinancial Eligibility (DP)). + # NOTE: 441 IAC 52.1 adjusts assistance standards each January 1 for the SSA + # cost-of-living adjustment but publishes no method, so this value stays at + # its 2026 level until a later schedule is added. reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - - title: SSA 2026 federally administered supplements, Iowa - href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f + - title: "Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Dependent Person Supplement #page 24-28" + href: https://hhs.iowa.gov/media/3987/download?inline=#page=24 + - title: 441 IAC 52.1 and 52.1(2) + href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 + - title: SSA POMS SI 01415.058 F.2 (TN 95, 08-26), Iowa payment levels + href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_couple_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_couple_amount.yaml deleted file mode 100644 index 9c2f78728b8..00000000000 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_couple_amount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -description: Iowa uses this amount as its couple federally administered family-life supplement. -values: - 2026-01-01: 801 - -metadata: - unit: currency-USD - period: month - label: Iowa SSA couple federally administered family-life supplement - reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - - title: SSA 2026 federally administered supplements, Iowa - href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_individual_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_individual_amount.yaml deleted file mode 100644 index 9c66a8e9636..00000000000 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_individual_amount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -description: Iowa uses this amount as its individual federally administered family-life supplement. -values: - 2026-01-01: 142 - -metadata: - unit: currency-USD - period: month - label: Iowa SSA individual federally administered family-life supplement - reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= - - title: SSA 2026 federally administered supplements, Iowa - href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_need.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_need.yaml deleted file mode 100644 index e946cde2ab0..00000000000 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_need.yaml +++ /dev/null @@ -1,11 +0,0 @@ -description: Iowa uses this amount as its family-life home need standard. -values: - 2026-01-01: 1_156 - -metadata: - unit: currency-USD - period: month - label: Iowa SSA family-life home need standard - reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_supplement.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_supplement.yaml new file mode 100644 index 00000000000..16a9bd986db --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_supplement.yaml @@ -0,0 +1,19 @@ +description: Iowa provides this amount as the maximum monthly family-life home supplement under the State Supplementary Assistance program. +values: + 2026-01-01: 162 + +metadata: + unit: currency-USD + period: month + label: Iowa SSA maximum family-life home supplement + # The family-life home standard is the SSI individual benefit rate plus this + # supplement ("$162 ($1,156 - $994 SSI standard)"). SSA pays at most $142, + # this supplement less the $20 general exclusion. The couple amount is twice + # the standard less the SSI couple rate and $20 (POMS code D Aged/Aged $801). + reference: + - title: "Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Family-Life Home Supplement #page 30,34-35" + href: https://hhs.iowa.gov/media/3987/download?inline=#page=30 + - title: 441 IAC 52.1 and 52.1(1) + href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 + - title: SSA POMS SI 01415.058 F.2 (TN 95, 08-26), Iowa code D payment levels + href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml index 186891d8424..2d78ce3b09d 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml @@ -1,11 +1,22 @@ -description: Iowa uses this amount as its maximum in-home care monthly cost per recipient. +description: Iowa limits the monthly in-home health-related care cost per recipient to this amount under the State Supplementary Assistance program. values: 2026-01-01: 480.55 metadata: unit: currency-USD period: month - label: Iowa SSA maximum in-home care monthly cost per recipient + label: Iowa SSA maximum in-home health-related care cost per recipient + # NOTE: 6-B Income (IHHRC) p.41: "If the care needed by the client is more + # expensive than these limits, the client is not eligible for a SSA payment + # for in-home health-related care." 441 IAC 177 instead limits countable + # income to "$480.55 per month if one needs care or $961.10 if both need care" + # and pays "the reasonable charges for such services up to and including + # $480.55". The IAC 2/5/25 edition has this text at 177.4(1)"f" and 177.10(3) + # (pages 2 and 5), and ARC 0460D (IAC 8/5/26, effective October 1, 2026) keeps + # it at 177.2(1)"f" and 177.8(3) (pages 1 and 4), so the conflict covers all + # of 2026. The model follows the manual (ia_ssa.yaml Cases 22-23). reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= + - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Income (IHHRC) + href: https://hhs.iowa.gov/media/3987/download?inline=#page=41 + - title: '441 IAC 177.2(1)"f" and 177.8(3) (IAB 8/5/26) #page 1,4' + href: https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml index 2075e98afe6..2621c2ca709 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml @@ -1,10 +1,16 @@ -description: Iowa uses this amount as its maximum residential care daily rate. +description: Iowa limits the residential care facility daily rate to this amount under the State Supplementary Assistance program. values: 2026-01-01: 38.47 metadata: unit: currency-USD + period: day label: Iowa SSA maximum residential care daily rate + # NOTE: 441 IAC 52.1 adjusts assistance standards each January 1 for the SSA + # cost-of-living adjustment but publishes no method, so this value stays at + # its 2026 level until a later schedule is added. reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= + - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Billing and Payments (RCF) + href: https://hhs.iowa.gov/media/3987/download?inline=#page=72 + - title: "441 IAC 52.1 and 52.1(3) #page 1-2" + href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml index bfd749596c7..9ca63d6130b 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml @@ -1,4 +1,4 @@ -description: Iowa uses this amount as its residential care personal needs allowance. +description: Iowa provides this amount as the monthly residential care personal needs allowance under the State Supplementary Assistance program. values: 2026-01-01: 130 @@ -6,6 +6,11 @@ metadata: unit: currency-USD period: month label: Iowa SSA residential care personal needs allowance + # NOTE: 441 IAC 52.1 adjusts assistance standards each January 1 for the SSA + # cost-of-living adjustment but publishes no method, so this value stays at + # its 2026 level until a later schedule is added. reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= + - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Personal Needs Allowance (RCF) + href: https://hhs.iowa.gov/media/3987/download?inline=#page=62 + - title: 441 IAC 52.1 and 52.1(3)"a"(2) + href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 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 a353885282d..f0d50a3be81 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,11 +1,13 @@ -description: Iowa uses this amount as its monthly Medicare and Medicaid supplement. +description: Iowa provides this amount as the monthly Supplement for Medicare and Medicaid Eligibles payment under the State Supplementary Assistance program. values: 2026-01-01: 1 metadata: unit: currency-USD period: month - label: Iowa SSA monthly Medicare and Medicaid supplement + label: Iowa SSA SMME payment reference: - - title: Iowa HHS Employees Manual 6-B, 2026 - href: https://hhs.iowa.gov/media/3987/download?inline= + - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Payments (SMME) + href: https://hhs.iowa.gov/media/3987/download?inline=#page=78 + - title: 441 IAC 52.1(7) + href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml index 700a09d03b2..14362cc9d80 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml @@ -1,10 +1,11 @@ -description: Iowa requires SMME countable income to exceed this share of the federal poverty guideline. +description: Iowa sets this share of the federal poverty guideline as the minimum income for the Supplement for Medicare and Medicaid Eligibles under the State Supplementary Assistance program. values: 2026-01-01: 1.2 metadata: unit: /1 - label: Iowa SMME minimum income FPG rate + period: year + label: Iowa SSA SMME minimum income poverty guideline rate reference: - - title: Iowa HHS Employees Manual 6-B, SMME income - href: https://hhs.iowa.gov/media/3987/download?inline= + - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Income (SMME) + href: https://hhs.iowa.gov/media/3987/download?inline=#page=77 diff --git a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml index 15ab54de16c..01fb7d281df 100644 --- a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml @@ -16,9 +16,9 @@ values: # exempts public assistance vendor payments only for medical assistance, # child care, energy assistance, migrant emergency assistance, housing # authority housing assistance, and emergency or special assistance that - # is not the normal grant. Countable components below exclude medical - # reimbursements and state-specific exempt payments; ordinary cash and - # room-and-board supplements count even when paid to a provider. + # is not the normal grant. None of the supplements below fall in those + # categories, so each counts, whether paid to the recipient or to a + # facility on the recipient's behalf. - ak_ssp - al_ssp # co_oap has an annual definition period; policyengine-core's @@ -34,9 +34,9 @@ values: - fl_oss - ga_ssp_person - hi_oss + - ia_ssa_countable_for_snap - id_aabd - in_ssp - - ia_ssa_countable_for_snap - ks_sspp - ky_ssp - la_oss @@ -101,7 +101,7 @@ values: metadata: reference: - - title: 7 CFR 273.9(b)(2) and (c)(1), (5) + - title: 7 CFR 273.9(b)(2) and (c)(1) href: https://www.law.cornell.edu/cfr/text/7/273.9 - title: POMS SI 01401.001 General Information about State Supplementation href: https://secure.ssa.gov/poms.nsf/lnx/0501401001 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 372b7be85d5..3087dbb91e3 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -998,16 +998,12 @@ programs: full_name: Iowa State Supplementary Assistance variable: ia_ssa parameter_prefix: gov.states.ia.hhs.ssa - verified_years: '2026' - notes: 2026 blind, dependent-person, family-life home, residential care, in-home health-related - care and SMME. Special categories require certification. Selected dependent budgets, - specialized parental/entry-month deeming, care deductions and SMME Medicaid-category - income require explicit inputs. Mandatory grandfathered and conditional resource payments - excluded. Ordinary child resource budgets include linked co-resident parents - and eligible-sibling allocation. Certified deeming exceptions, step-only - households and other state-only sibling eligibility require deemed-resource - inputs for each affected child. Mixed-blind dependent couple rate follows the state manual and SSA per-blind-person - definition rather than inconsistent C rows in the federal table. + verified_years: "2026" + notes: >- + Models 2026 blind, dependent-person, family-life home, residential + care, in-home health-related care and SMME supplements; special + categories need certification inputs. Mandatory minimum-income-level + and conditional-benefit payments are not modeled. - 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 13681678d0c..35316be759d 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 @@ -307,6 +307,8 @@ ia_ssa_ihhrc_monthly_cost: 400 social_security_retirement: 6_516 output: + # SSI 994 - (543 - 20) = 471; participation 543 + 471 - 994 = 20. + ia_ssa_ihhrc_participation: 20 ia_ssa: 380 - name: Case 25, IHHRC medical deductions reduce participation. @@ -335,7 +337,7 @@ ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 social_security_retirement: 16_800 - ia_ssa_care_days: 16 + ia_ssa_care_partial_month_days: 16 ia_ssa_ihhrc_initial_partial_month: true output: ia_ssa: 206.4516129032258 @@ -933,3 +935,357 @@ 2026: IA output: ia_ssa: [0, 400] + +- name: Case 44, partial in-home care days on one resident leave another resident's full month unchanged. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + social_security_retirement: + 2026: 16_800 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + ia_ssa_care_partial_month_days: 16 + ia_ssa_ihhrc_initial_partial_month: true + person2: + age: + 2026: 65 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family: + members: [person1, person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: + 2026: IA + output: + # person1: no participation in the first partial month; 400 * 16 / 31 = 206.45. + # person2: SSI 994 less the 994 home maintenance allowance leaves no + # participation, so the full 400 cost is paid. + ia_ssa_care_partial_month_days: [16, 0] + ia_ssa_ihhrc_participation: [0, 0] + ia_ssa_ihhrc_amount: [206.45, 400] + ia_ssa: [206.45, 400] + +- name: Case 45, partial residential care days on one resident leave another resident's full month unchanged. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + ia_ssa_category: RESIDENTIAL_CARE + ia_ssa_rcf_daily_rate: 38.47 + # Entry on January 7: the day of entry through January 31. + ia_ssa_care_partial_month_days: 25 + person2: + age: + 2026: 65 + ia_ssa_category: RESIDENTIAL_CARE + ia_ssa_rcf_daily_rate: 38.47 + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family: + members: [person1, person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: + 2026: IA + output: + # Each resident has SSI 994, so participation is 994 - 130 = 864. + # person1: 38.47 * 25 = 961.75 - 864 = 97.75. + # person2: 38.47 * 31 = 1,192.57 - 864 = 328.57. + ia_ssa: [97.75, 328.57] + +- name: Case 46, the initial partial-month flag and days apply only to the entry month. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: IA + age: 65 + social_security_retirement: 16_800 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: + 2026-01: 400 + 2026-02: 400 + ia_ssa_care_partial_month_days: + 2026-01: 16 + ia_ssa_ihhrc_initial_partial_month: + 2026-01: true + output: + # January: no participation; 400 * 16 / 31 = 206.45. + # February: participation 1,400 - 994 = 406 is at least the 400 cost. + ia_ssa_ihhrc_initial_partial_month: + 2026-01: true + 2026-02: false + ia_ssa_care_partial_month_days: + 2026-01: 16 + 2026-02: 0 + ia_ssa_ihhrc_participation: + 2026-01: 0 + 2026-02: 406 + ia_ssa: + 2026-01: 206.45 + 2026-02: 0 + +- name: Case 47, a one-month care deduction does not carry into the next month. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: IA + age: 65 + social_security_retirement: 16_800 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: + 2026-01: 400 + 2026-02: 400 + ia_ssa_care_additional_deductions: + 2026-01: 100 + output: + # January: participation 1,400 - 994 - 100 = 306, so 400 - 306 = 94. + # February: participation 1,400 - 994 = 406, so nothing is paid. + ia_ssa_care_additional_deductions: + 2026-01: 100 + 2026-02: 0 + ia_ssa: + 2026-01: 94 + 2026-02: 0 + +- name: Case 48, a residential care applicant over the SSI income limit need not take up SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + social_security_retirement: 13_200 + takes_up_ssi_if_eligible: false + ia_ssa_category: RESIDENTIAL_CARE + ia_ssa_rcf_daily_rate: 38.47 + output: + # SSI countable income 1,100 - 20 = 1,080 exceeds 994, so SSI would pay nothing. + # Participation 1,100 - 130 = 970; 38.47 * 31 = 1,192.57 - 970 = 222.57. + uncapped_ssi: -86 + ia_ssa_nonfinancial_eligible: true + ia_ssa: 222.57 + +- name: Case 49, an in-home care applicant over the SSI income limit need not take up SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + social_security_retirement: 13_200 + takes_up_ssi_if_eligible: false + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + output: + # Participation 1,100 - 994 = 106; 400 - 106 = 294. + ia_ssa_nonfinancial_eligible: true + ia_ssa_ihhrc_participation: 106 + ia_ssa: 294 + +- name: Case 50, an SMME applicant over the SSI income limit need not take up SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + social_security_retirement: 24_000 + takes_up_ssi_if_eligible: false + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + output: + # SMME income 2,000 - 20 = 1,980 exceeds 1.2 * 15,960 / 12 = 1,596. + ia_ssa_nonfinancial_eligible: true + ia_ssa_smme_countable_income: 1_980 + ia_ssa: 1 + +- name: Case 51, 2027 blind supplement. + period: 2027-01 + absolute_error_margin: 0.01 + input: + state_code: + 2027: IA + age: + 2027: 65 + is_blind: true + output: + ia_ssa: 22 + +- name: Case 52, 2027 residential care participation uses the 2027 SSI rate. + period: 2027-01 + absolute_error_margin: 0.01 + input: + state_code: + 2027: IA + age: + 2027: 65 + ia_ssa_category: RESIDENTIAL_CARE + ia_ssa_rcf_daily_rate: 38.47 + output: + # SSI 1,029; participation 1,029 - 130 = 899; 38.47 * 31 = 1,192.57 - 899 = 293.57. + ia_ssa: 293.57 + +- name: Case 53, 2027 family-life home standard follows the SSI rate. + period: 2027-01 + absolute_error_margin: 0.01 + input: + state_code: + 2027: IA + age: + 2027: 65 + ia_ssa_category: FAMILY_LIFE_HOME + ia_ssa_care_countable_income: 1_170 + output: + # Standard 1,029 + 162 = 1,191, so 1,170 qualifies (the 2026 standard was + # 1,156). With no other countable SSI income, SSA pays 162 - 20 = 142. + ia_ssa_federal: 142 + +- name: Case 54, 2027 family-life home income at the standard is ineligible. + period: 2027-01 + absolute_error_margin: 0.01 + input: + state_code: + 2027: IA + age: + 2027: 65 + ia_ssa_category: FAMILY_LIFE_HOME + ia_ssa_care_countable_income: 1_191 + output: + # Income must be below the 1,029 + 162 = 1,191 standard. + ia_ssa_federal: 0 + +- name: Case 55, negative self-employment income does not inflate the residential care payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + self_employment_income: -60_000_000 + ia_ssa_category: RESIDENTIAL_CARE + ia_ssa_rcf_daily_rate: 38.47 + output: + # Countable earnings floor at 0: SSI 994, participation 864, 1,192.57 - 864. + ia_ssa: 328.57 + +- name: Case 56, SMME income at 120 percent of poverty is not above the minimum. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + ia_ssa_smme_countable_income: 1_596 + output: + # 1.2 * 15,960 / 12 = 1,596. + ia_ssa: 0 + +- name: Case 57, SMME income one cent above 120 percent of poverty. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + ia_ssa_smme_countable_income: 1_596.01 + output: + ia_ssa: 1 + +- name: Case 58, manual example excludes one-third of a child's child support from participation. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + person2: + age: + 2026: 10 + person_id: + 2026: 2 + parent_1_id: + 2026: 1 + # 6-B example: a $1,500 child support payment from an absent parent. + child_support_received: + 2026: 18_000 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + marital_units: + parent: + members: [person1] + child: + members: [person2] + families: + family: + members: [person1, person2] + tax_units: + family: + members: [person1, person2] + spm_units: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: + 2026: IA + output: + # SSI countable income 1,500 - 20 = 1,480 exceeds 994, so SSI is 0. + # Iowa: 1,500 - 500 one-third exclusion = 1,000; participation 1,000 - 994 = 6. + ssi: [0, 0] + ia_ssa_care_countable_income: [0, 1_000] + ia_ssa_ihhrc_participation: [0, 6] + ia_ssa: [0, 394] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.yaml new file mode 100644 index 00000000000..61578c9b75a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.yaml @@ -0,0 +1,310 @@ +# Iowa 6-B in-home health-related care parental income deeming worked examples. +- name: Case 1, manual example of a mother with unemployment benefits only. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + # 6-B example: unemployment benefits of $1,050 a month. + unemployment_compensation: + 2026: 12_600 + person2: + age: + 2026: 10 + person_id: + 2026: 2 + parent_1_id: + 2026: 1 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + marital_units: + parent: + members: [person1] + child: + members: [person2] + families: + family: + members: [person1, person2] + tax_units: + family: + members: [person1, person2] + spm_units: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: + 2026: IA + output: + # Iowa: 1,050 - 994 SSI allowance for the mother = 56 deemed. + # SSI deems 1,050 - 20 - 994 = 36, less the child's 20 exclusion: 994 - 16 = 978. + # Participation 56 + 978 - 994 = 40, so 400 - 40 = 360 is paid. + ia_ssa_income_deemed_from_parents: [0, 56] + ssi: [0, 978] + people: + person2: + ia_ssa_care_countable_income: 1_034 + ia_ssa_ihhrc_participation: 40 + ia_ssa: [0, 360] + +- name: Case 2, manual D family example with earnings only and two ineligible siblings. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + # 6-B example: Mr. D has earnings of $4,200 a month. + employment_income_before_lsr: + 2026: 50_400 + person2: + age: + 2026: 40 + person_id: + 2026: 2 + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + person4: + age: + 2026: 8 + person_id: + 2026: 4 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + person5: + age: + 2026: 8 + person_id: + 2026: 5 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + marital_units: + parents: + members: [person1, person2] + child1: + members: [person3] + child2: + members: [person4] + child3: + members: [person5] + families: + family: + members: [person1, person2, person3, person4, person5] + tax_units: + family: + members: [person1, person2, person3, person4, person5] + spm_units: + unit: + members: [person1, person2, person3, person4, person5] + households: + home: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: IA + output: + # Iowa: 4,200 - 65 - 2,982 (double the couple allowance) - 2 * 497 = 159. + # SSI deems (4,200 - 994 - 85) / 2 - 1,491 = 69.50, less 20: 994 - 49.50 = 944.50. + # Participation 159 + 944.50 - 994 = 109.50, so 400 - 109.50 = 290.50 is paid. + ia_ssa_income_deemed_from_parents: [0, 0, 159, 0, 0] + ssi: [0, 0, 944.5, 0, 0] + people: + person3: + ia_ssa_care_countable_income: 1_103.5 + ia_ssa_ihhrc_participation: 109.5 + ia_ssa: [0, 0, 290.5, 0, 0] + +- name: Case 3, manual E family example with siblings who have Social Security income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + # 6-B example: Mr. E has earnings of $4,000 a month. + employment_income_before_lsr: + 2026: 48_000 + person2: + age: + 2026: 40 + person_id: + 2026: 2 + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + person4: + age: + 2026: 8 + person_id: + 2026: 4 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + # 6-B example: each ineligible child has $150 a month of Social Security. + social_security_dependents: + 2026: 1_800 + person5: + age: + 2026: 8 + person_id: + 2026: 5 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + social_security_dependents: + 2026: 1_800 + marital_units: + parents: + members: [person1, person2] + child1: + members: [person3] + child2: + members: [person4] + child3: + members: [person5] + families: + family: + members: [person1, person2, person3, person4, person5] + tax_units: + family: + members: [person1, person2, person3, person4, person5] + spm_units: + unit: + members: [person1, person2, person3, person4, person5] + households: + home: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: IA + output: + # Iowa: 4,000 - 65 - 2,982 - 2 * (497 - 150) = 259. + # SSI deems (4,000 - 694 - 85) / 2 - 1,491 = 119.50, less 20: 994 - 99.50 = 894.50. + # Participation 259 + 894.50 - 994 = 159.50, so 400 - 159.50 = 240.50 is paid. + ia_ssa_income_deemed_from_parents: [0, 0, 259, 0, 0] + ssi: [0, 0, 894.5, 0, 0] + people: + person3: + ia_ssa_care_countable_income: 1_153.5 + ia_ssa_ihhrc_participation: 159.5 + ia_ssa: [0, 0, 240.5, 0, 0] + +- name: Case 4, manual G family example with earned and unearned parental income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + # 6-B example: Mr. G has a retirement pension of $900 a month. + taxable_private_pension_income: + 2026: 10_800 + person2: + age: + 2026: 40 + person_id: + 2026: 2 + # 6-B example: Mrs. G has earnings of $1,500 a month. + employment_income_before_lsr: + 2026: 18_000 + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + person4: + age: + 2026: 8 + person_id: + 2026: 4 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + marital_units: + parents: + members: [person1, person2] + child1: + members: [person3] + child2: + members: [person4] + families: + family: + members: [person1, person2, person3, person4] + tax_units: + family: + members: [person1, person2, person3, person4] + spm_units: + unit: + members: [person1, person2, person3, person4] + households: + home: + members: [person1, person2, person3, person4] + state_code: + 2026: IA + output: + # Iowa: (1,500 - 65) / 2 + 900 = 1,617.50 - 1,491 = 126.50 - 497 < 0, so 0. + # The child receives the full SSI 994; participation 994 - 994 = 0. + ia_ssa_income_deemed_from_parents: [0, 0, 0, 0] + ssi: [0, 0, 994, 0] + people: + person3: + ia_ssa_ihhrc_participation: 0 + ia_ssa: [0, 0, 400, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.yaml new file mode 100644 index 00000000000..7fa2ff3314b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.yaml @@ -0,0 +1,75 @@ +- name: Case 1, aged citizen in an ordinary living arrangement. + period: 2026-01 + input: + state_code: + 2026: IA + age: + 2026: 65 + output: + ia_ssa_nonfinancial_eligible: true + +- name: Case 2, a 64-year-old who is neither blind nor disabled is not aged. + period: 2026-01 + input: + state_code: + 2026: IA + age: + 2026: 64 + output: + ia_ssa_nonfinancial_eligible: false + +- name: Case 3, an incarcerated blind person is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + is_blind: true + is_incarcerated: true + output: + ia_ssa_nonfinancial_eligible: false + ia_ssa: 0 + +- name: Case 4, an undocumented blind person is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + is_blind: true + immigration_status: + 2026: UNDOCUMENTED + output: + ia_ssa_nonfinancial_eligible: false + ia_ssa: 0 + +- name: Case 5, a blind person with no eligible arrangement is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + is_blind: true + ia_ssa_category: NONE + output: + ia_ssa_nonfinancial_eligible: false + ia_ssa: 0 + +- name: Case 6, a blind person who would qualify for SSI but declines it is ineligible. + period: 2026-01 + input: + state_code: + 2026: IA + age: + 2026: 65 + is_blind: true + takes_up_ssi_if_eligible: false + output: + # With no income, uncapped SSI is 994, so the applicant must apply for SSI. + ia_ssa_nonfinancial_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml index 4106fb08f26..a4329d445fe 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.yaml @@ -230,10 +230,9 @@ 2026: IA output: ia_ssa_resources_deemed_from_parents: [0, 0, 0, 2_500, 0] - ia_ssa: [0, 0, 400, 0, 0 + ia_ssa: [0, 0, 400, 0, 0] # Child-specific parental budgets and sibling allocation: SI 01330.200/.280. -] - name: Case 5, Children with different linked parent sets do not share a resource allocation. period: 2026-06 @@ -312,3 +311,114 @@ output: ia_ssa_resources_deemed_from_parents: [0, 0, 2_500, 3_500] ia_ssa: [0, 0, 0, 0] + +- name: Case 6, a co-resident stepparent's resources are deemed with the parent's. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 38 + person_id: + 2026: 1 + person2: + age: + 2026: 40 + person_id: + 2026: 2 + bank_account_assets: + 2026: 5_600 + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + marital_units: + parents: + members: [person1, person2] + child: + members: [person3] + families: + family: + members: [person1, person2, person3] + tax_units: + family: + members: [person1, person2, person3] + spm_units: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: + 2026: IA + output: + # person2 is the mother's spouse but not a named parent. 20 CFR 416.1202(b)(1) + # deems a stepparent's resources and allows 3,000 for a parent and spouse: + # 5,600 - 3,000 = 2,600, above the child's 2,000 limit. + ia_ssa_resources_deemed_from_parents: [0, 0, 2_600] + ia_ssa_eligible: [false, false, false] + ia_ssa: [0, 0, 0] + +- name: Case 7, manual Child A example deems one parent's bonds above the one-parent allowance. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + # 6-B example: the parent has $2,200 in government bonds. + bond_assets: + 2026: 2_200 + person2: + age: + 2026: 10 + person_id: + 2026: 2 + parent_1_id: + 2026: 1 + # 6-B example: Child A has $900 in a savings account. + bank_account_assets: + 2026: 900 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + marital_units: + parent: + members: [person1] + child: + members: [person2] + families: + family: + members: [person1, person2] + tax_units: + family: + members: [person1, person2] + spm_units: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: + 2026: IA + output: + # 2,200 - 2,000 = 200 deemed; 900 + 200 = 1,100 is within the 2,000 limit. + ia_ssa_resources_deemed_from_parents: [0, 200] + ia_ssa_eligible: [false, true] + ia_ssa: [0, 400] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml index dbde9194455..3c7b6bc8d5d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml @@ -150,16 +150,21 @@ output: ia_ssa: [395, 395] -- name: Case 8, annual blind allowance and SNAP income. +- name: Case 8, annual blind allowance in SNAP income and benefit totals. period: 2026 absolute_error_margin: 0.01 input: age: 65 state_code: IA is_blind: true + # SNAP take-up is off so the benefit total isolates SSI and Iowa SSA. + takes_up_snap_if_eligible: false output: + # 22 * 12 = 264; SSI 994 * 12 = 11,928; 11,928 + 264 = 12,192. ia_ssa: 264 snap_unearned_income: 12_192 + household_state_benefits: 264 + spm_unit_benefits: 12_192 - name: Case 9, Iowa in-home reimbursement is excluded while blind cash is counted. period: 2026 @@ -171,6 +176,38 @@ ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 4_800 output: + # (400 + 22) * 12 = 5,064; only the blind 22 * 12 = 264 is countable. ia_ssa: 5_064 + ia_ssa_countable_for_snap: 264 + ia_ssa_countable_for_hud: 264 snap_unearned_income: 12_192 hud_unearned_income: 12_192 + +- name: Case 10, 2027 family-life home couple amount follows the SSI rates. + period: 2027-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + ia_ssa_category: FAMILY_LIFE_HOME + person2: + age: 65 + ia_ssa_category: FAMILY_LIFE_HOME + marital_units: + couple: + members: [person1, person2] + households: + hh: + members: [person1, person2] + state_code: IA + output: + # The 2027 SSI couple rate of 1,544 is split 772 each, which is each + # spouse's care income. + # Standard 1,029 + 162 = 1,191; couple amount 2 * 1,191 - 1,544 - 20 = 818, + # split 409 each (801 and 400.50 in 2026). + # The SSI-only couple shares one 20 top-up: 409 + 10 = 419. + ssi: [772, 772] + ia_ssa_care_countable_income: [772, 772] + ia_ssa_federal: [409, 409] + ia_ssa: [419, 419] diff --git a/policyengine_us/variables/gov/states/_ssp_parental_resources.py b/policyengine_us/variables/gov/states/_ssp_parental_resources.py deleted file mode 100644 index b2d76b4a130..00000000000 --- a/policyengine_us/variables/gov/states/_ssp_parental_resources.py +++ /dev/null @@ -1,76 +0,0 @@ -"""Co-resident parental resources shared by state supplement calculations.""" - -import numpy as np - -from policyengine_us.variables.household.demographic.person._parent_links import ( - co_resident_parent_indices, - has_parent_ids, - household_member_indices, - unlinked_parent, -) - - -def ssp_parental_resources(person, period, parameters, exclude_ssi_parents=False): - """Return the parent pair and resources above its SSI allowance. - - Explicit links identify natural, adoptive and step parents in this - household. Without a child's links, use only explicitly identified - unlinked parents in the same family and household. More than two such - candidates requires parent links or a certified deemed-resource input. - """ - year = period.this_year - first, second = co_resident_parent_indices(person, year) - unlinked = ~has_parent_ids(person, year) - parent = unlinked_parent(person, year) - family = person.family.reference_entity.members_entity_id - own_row = np.arange(person.count) - candidates = np.zeros(person.count, dtype=int) - fallback_first = np.full(person.count, -1, dtype=int) - fallback_second = np.full(person.count, -1, dtype=int) - for member in household_member_indices(person): - match = ( - (member >= 0) - & (member != own_row) - & parent[member] - & (family[member] == family) - ) - fallback_first = np.where(match & (candidates == 0), member, fallback_first) - fallback_second = np.where(match & (candidates == 1), member, fallback_second) - candidates = candidates + match - usable = unlinked & (candidates <= 2) - first = np.where(usable, fallback_first, first) - second = np.where(usable, fallback_second, second) - # Sorting makes sibling membership independent of the parent-slot order. - first, second = np.minimum(first, second), np.maximum(first, second) - resources = person("ssi_countable_resources", year).astype(np.float64) - if exclude_ssi_parents: - resources = np.where(person("ssi", period) > 0, 0, resources) - total = np.where(first >= 0, resources[first], 0) + np.where( - second >= 0, resources[second], 0 - ) - parents = (first >= 0).astype(int) + (second >= 0) - limit = parameters(period).gov.ssa.ssi.eligibility.resources.limit - allowance = np.where(parents > 1, limit.couple, limit.individual) - return first, second, np.maximum(total - allowance, 0) - - -def ssp_sibling_resource_share(person, first, second, excess, candidates, own, limit): - """Allocate to otherwise eligible children, removing resource failures. - - SI 01330.200/.280 require reallocation when a child's own resources - plus their share disqualify them. Children with different parent sets - do not reduce one another's deemed resources. - """ - eligible = candidates & (own <= limit) - share = excess.copy() - for _ in range(int(np.max(person.household.nb_persons(), initial=0)) + 1): - count = np.zeros(person.count, dtype=int) - for member in household_member_indices(person): - same_parents = (first == first[member]) & (second == second[member]) - count = count + ((member >= 0) & same_parents & eligible[member]) - share = excess / np.maximum(count, 1) - remaining = eligible & (own + share <= limit) - if np.array_equal(remaining, eligible): - break - eligible = remaining - return share 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 98269c7f722..469062191d7 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 @@ -7,7 +7,14 @@ class ia_ssa(Variable): label = "Iowa State Supplementary Assistance" definition_period = MONTH unit = USD - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) + reference = ( + # Iowa Code 249.3 + "https://www.legis.iowa.gov/docs/code/249.pdf#page=1", + # 441 IAC 52.1; PDF pages 1-2 + "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", + # PDF pages 35, 41-49, 59-74, 76-78 + "https://hhs.iowa.gov/media/3987/download?inline=#page=35", + ) defined_for = "ia_ssa_eligible" def formula(person, period, parameters): @@ -18,54 +25,51 @@ def formula(person, period, parameters): federally_paid = person("ia_ssa_federal", period) income = person("ia_ssa_care_countable_income", period) extra = max_(person("ia_ssa_care_additional_deductions", period), 0) - days = clip(person("ia_ssa_care_days", period), 0, period.days) + partial = person("ia_ssa_care_partial_month_days", period) + days = where(partial > 0, min_(partial, period.days), period.days) # RCF income eligibility uses a 31-day ceiling; payment uses the # actual covered days billed by the provider. rate = min_(max_(person("ia_ssa_rcf_daily_rate", period), 0), p.rcf_daily_limit) rcf_participation = max_(income - p.rcf_personal_needs - extra, 0) rcf = max_(rate * days - rcf_participation, 0) - home = category == c.IN_HOME_CARE - cost = max_(person("ia_ssa_ihhrc_monthly_cost", period), 0) - within_limit = (cost <= p.ihhrc_cost_limit) & home - has_spouse = person.marital_unit.nb_persons() == 2 - maintenance = where( - has_spouse, federal.amount.couple, federal.amount.individual - ) - deductions = where(has_spouse, person.marital_unit.sum(extra), extra) - participation = max_(income - maintenance - deductions, 0) - participation = where( - person("ia_ssa_ihhrc_initial_partial_month", period), 0, participation - ) - covered_cost = cost * days / period.days * within_limit - total_cost = person.marital_unit.sum(covered_cost) - # Allocate a common household contribution proportionately to the - # approved costs, preserving the household's total payable benefit. - ihhrc = ( - max_(total_cost - participation, 0) * covered_cost / max_(total_cost, 1e-9) - ) - # The additional Department payment is for SSI-only FLH recipients. - # One $20 general exclusion applies to the eligible couple. + ihhrc = person("ia_ssa_ihhrc_amount", period) + # 6-B Making the Family-Life Home Payment: "For a recipient who has + # only SSI and no other income (and hence no $20 to disregard), an + # additional $20 payment is necessary". The $20 is SSI's general income + # exclusion, so the federal parameter is used. Only positive amounts + # count as other income, and the eligible couple shares one $20. + receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) joint = person("ssi_couple_computation_applies", period) sources = federal.income.sources - other_income = sum( - max_(person(name, period), 0) - for name in list(sources.earned) + list(sources.unearned) + has_other_income = np.zeros(person.count, dtype=bool) + for source in list(sources.earned) + list(sources.unearned): + has_other_income = has_other_income | (person(source, period) > 0) + has_other_income = where( + joint, person.marital_unit.any(has_other_income), has_other_income ) - other_income = where(joint, person.marital_unit.sum(other_income), other_income) flh = category == c.FAMILY_LIFE_HOME recipients = person.marital_unit.sum(flh) top_up = ( - (other_income == 0) - * (person("ssi", period) > 0) + ~has_other_income + * receives_ssi * federal.income.exclusions.general / where(joint, max_(recipients, 1), 1) ) + # The SMME standard uses the federal poverty guideline for the + # recipient's marital unit (6-B Income (SMME)). size = person.marital_unit.nb_persons() fpg = parameters(period).gov.hhs.fpg poverty = ( fpg.first_person.CONTIGUOUS_US + (size - 1) * fpg.additional_person.CONTIGUOUS_US ) / MONTHS_IN_YEAR + # NOTE: Iowa Code 249.3(4)(g) requires "income of at least one hundred + # twenty percent of the federal poverty level", in a subsection that + # opens "At the discretion of the department". 441 IAC 51.7(6) says + # income "must exceed 120 percent of the federal poverty level", and + # 6-B Income (SMME) p.77 says it "also exceeds 120% of the federal + # poverty level". The model follows 51.7(6) and the manual, so income + # of exactly 120% does not qualify (ia_ssa.yaml Cases 56-57). smme = ( person("ia_ssa_smme_coverage_eligible", period) & ( @@ -75,7 +79,12 @@ def formula(person, period, parameters): & (federally_paid == 0) ) state = select( - [category == c.RESIDENTIAL_CARE, home, flh, category == c.SMME], + [ + category == c.RESIDENTIAL_CARE, + category == c.IN_HOME_CARE, + flh, + category == c.SMME, + ], [rcf, ihhrc, top_up, smme * p.smme_amount], default=0, ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_additional_deductions.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_additional_deductions.py index c14c751ce3b..92984389ce0 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_additional_deductions.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_additional_deductions.py @@ -7,5 +7,15 @@ class ia_ssa_care_additional_deductions(Variable): label = "Iowa SSA approved additional care income deductions" definition_period = MONTH unit = USD - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) - documentation = "Verified dependent/spouse allocations and unmet medical needs; for residential care also approved first-month community expenses and work-related deductions. Excludes the built-in maintenance allowance and general/ordinary earnings disregards." + defined_for = StateCode.IA + documentation = "Verified monthly deductions from care income beyond those the model applies: dependent and spouse allocations and unmet medical needs, and for residential care also approved first-month expenses of the previous living arrangement and work-related deductions. Excludes the home maintenance or personal needs allowance and the $65 and one-half earnings exclusions. Key each amount to its month; a yearly entry is spread evenly over the months." + reference = ( + # 441 IAC 52.1(3)"a" + "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", + # PDF pages 42-43, 61-64 + "https://hhs.iowa.gov/media/3987/download?inline=#page=42", + ) + + def formula(person, period, parameters): + # A formula stops a one-month input from carrying into later months. + return 0 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py index 7ba629b7089..7db74fb7456 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py @@ -10,8 +10,14 @@ class ia_ssa_care_countable_income(Variable): label = "Iowa SSA care countable income without general disregard" definition_period = MONTH unit = USD - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) - documentation = "Whole marital-group income for adult in-home care; individual income for other care. Override for state-specific parental deeming, first-month spouse deeming or deductions absent from federal SSI income inputs." + defined_for = StateCode.IA + documentation = "Whole marital-group income for adult in-home care; individual income for other care. A child in in-home care receives income deemed from parents under the Iowa method. First-month spouse deeming and deductions absent from the federal SSI income inputs are not modeled." + reference = ( + # 441 IAC 52.1(3)"a" + "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", + # PDF pages 34, 41-42, 49, 59-63 + "https://hhs.iowa.gov/media/3987/download?inline=#page=34", + ) def formula(person, period, parameters): category = person("ia_ssa_category", period) @@ -24,6 +30,9 @@ def formula(person, period, parameters): - person("ssi_blind_or_disabled_working_student_exclusion", period), 0, ) + # 6-B excludes one-third of child support a child receives from an + # absent parent. Federal SSI does not apply 20 CFR 416.1124(c)(11) yet + # (issue 10242), so the shared federal share is read here directly. unearned = max_( person("ssi_unearned_income", period) - person("interest_income", period) @@ -33,9 +42,14 @@ def formula(person, period, parameters): * parameters(period).gov.ssa.ssi.income.exclusions.child_support_share, 0, ) - unearned = unearned + ~adult * person( - "ssi_unearned_income_deemed_from_ineligible_parent", period + # 6-B: "do not rely on SSI deeming calculations for children" in + # in-home health-related care; other care uses SSI parental deeming. + deemed = where( + home, + person("ia_ssa_income_deemed_from_parents", period), + person("ssi_unearned_income_deemed_from_ineligible_parent", period), ) + unearned = unearned + ~adult * deemed benefit = person("ssi", period) earned = where(combine, person.marital_unit.sum(earned), earned) unearned = where(combine, person.marital_unit.sum(unearned), unearned) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_days.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_days.py deleted file mode 100644 index 85f7968e0cb..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_days.py +++ /dev/null @@ -1,13 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_care_days(Variable): - value_type = int - entity = Person - label = "Iowa SSA covered care days" - definition_period = MONTH - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) - documentation = "Covered residential days include admission but not discharge/death, plus authorized reserve bed days. For IHHRC, days of approved services in a partial month." - - def formula(person, period, parameters): - return period.days diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_partial_month_days.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_partial_month_days.py new file mode 100644 index 00000000000..bb7940fbbd3 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_partial_month_days.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ia_ssa_care_partial_month_days(Variable): + value_type = int + entity = Person + label = "Iowa SSA covered care days in a partial month" + definition_period = MONTH + defined_for = StateCode.IA + default_value = 0 + documentation = "Covered days in a month that is not fully covered. For residential care, count the day of entry but not the day of discharge or death, plus authorized reserve bed days; for in-home health-related care, count the days of approved services. Leave at 0 for a full month; a value of at least the month's length is also a full month. Key the entry to its month (for example 2026-01: 15)." + reference = ( + # 441 IAC 52.1(3)"b", "e" and "f" + "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=2", + # PDF pages 42, 71-72 + "https://hhs.iowa.gov/media/3987/download?inline=#page=42", + ) + + def formula(person, period, parameters): + # A formula stops a one-month input from carrying into later months. + return 0 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_category.py index d3fa9f8e502..ab156f123e1 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 @@ -18,7 +18,8 @@ class ia_ssa_category(Variable): definition_period = MONTH possible_values = IASSACategory default_value = IASSACategory.REGULAR - reference = "https://hhs.iowa.gov/media/3987/download?inline=" + # PDF pages 5-6, 20, 24, 30, 41, 59, 76 + reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=5" documentation = """ Special categories require agency certification of the dependency or care arrangement, benefit pursuit, and procedural eligibility. DEPENDENT_PERSON diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_for_hud.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_for_hud.py new file mode 100644 index 00000000000..454d781eb6a --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_for_hud.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ia_ssa_countable_for_hud(Variable): + value_type = float + entity = Person + label = "Iowa State Supplementary Assistance countable for HUD" + definition_period = MONTH + unit = USD + defined_for = StateCode.IA + # 24 CFR 5.609(b)(6) and (b)(19) + reference = "https://www.ecfr.gov/current/title-24/section-5.609#p-5.609(b)(6)" + + def formula(person, period, parameters): + # 24 CFR 5.609(b)(6) excludes amounts "specifically for, or in + # reimbursement of, the cost of health and medical care expenses", and + # (b)(19) excludes state agency payments "to enable a family member who + # has a disability to reside in the family's assisted unit". Both cover + # the in-home health-related care payment; the blind supplement paid + # alongside it remains income. + category = person("ia_ssa_category", period) + home_care = category == category.possible_values.IN_HOME_CARE + return where( + home_care, person("ia_ssa_federal", period), person("ia_ssa", period) + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_for_snap.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_for_snap.py index 990aee2c60b..3f1b093f6e4 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_for_snap.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_countable_for_snap.py @@ -7,13 +7,19 @@ class ia_ssa_countable_for_snap(Variable): label = "Iowa State Supplementary Assistance countable for SNAP" definition_period = MONTH unit = USD - reference = "https://hhs.iowa.gov/media/3997#page=34" + defined_for = StateCode.IA + reference = ( + "https://hhs.iowa.gov/media/3997#page=34", + "https://www.ecfr.gov/current/title-7/section-273.9#p-273.9(c)(5)", + ) def formula(person, period, parameters): + # Iowa SNAP manual 7-E: "Exclude State Supplementary Assistance payments + # made for in-home health-related care as a reimbursement" (7 CFR + # 273.9(c)(5)). The blind supplement paid alongside it remains + # countable cash assistance. category = person("ia_ssa_category", period) home_care = category == category.possible_values.IN_HOME_CARE - # The blind supplement remains ordinary cash assistance when paid - # alongside the excluded reimbursement for in-home health care. return where( home_care, person("ia_ssa_federal", period), person("ia_ssa", period) ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_dependent_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_dependent_countable_income.py index 6b1e3d0349e..5b496919f75 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_dependent_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_dependent_countable_income.py @@ -7,5 +7,6 @@ class ia_ssa_dependent_countable_income(Variable): label = "Countable income of Iowa SSA selected dependent" definition_period = MONTH unit = USD - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) - documentation = "Verified dependent income after 6-B deductions, including the special parent-of-child calculation and only one $20 exclusion per dependent group. The dependent does not receive the recipient's half-earnings exclusion." + # PDF pages 24-28 + reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=24" + documentation = "Verified dependent income after 6-B deductions, including the special parent-of-child calculation and only one $20 exclusion per dependent group. The dependent does not receive the recipient's half-earnings exclusion. An entry carries into later months until it is changed." 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 920efa9ebee..d001219fec8 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 @@ -6,8 +6,14 @@ class ia_ssa_eligible(Variable): entity = Person label = "Iowa SSA non-income eligibility" definition_period = MONTH - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) defined_for = StateCode.IA + reference = ( + # Iowa Code 249.3 + "https://www.legis.iowa.gov/docs/code/249.pdf#page=1", + # PDF pages 6-12 + "https://hhs.iowa.gov/media/3987/download?inline=#page=6", + "https://www.ecfr.gov/current/title-20/section-416.1202", + ) def formula(person, period, parameters): category = person("ia_ssa_category", period) @@ -21,18 +27,16 @@ def formula(person, period, parameters): | (category == c.DEPENDENT_PERSON) | (category == c.FAMILY_LIFE_HOME) ) + # 6-B Resources: "When the applicant is living with a spouse, count the + # spouse's resources." couple = (person.marital_unit.nb_persons() == 2) & (community | joint) resource = where(couple, person.marital_unit.sum(resource), resource) resource = resource + person("ia_ssa_resources_deemed_from_parents", period) - p = parameters(period).gov.ssa.ssi.eligibility.resources.limit - immigration = person("immigration_status", period.this_year) - citizen = immigration == immigration.possible_values.CITIZEN - immigrant = person("is_ssi_qualified_noncitizen", period.this_year) - return ( - person("is_ssi_aged_blind_disabled", period.this_year) - & (citizen | immigrant) - & (resource <= where(couple, p.couple, p.individual)) - & (category != c.NONE) - & ~person("is_incarcerated", period) - & person("takes_up_ssi_if_eligible", period) + # 6-B Resources prints "$2,000 for an individual" and "$3,000 for a + # married couple living together" under 20 CFR 416.1202; these equal + # the SSI limits, so the federal parameters are used and an SSI reform + # carries over to Iowa. + limit = parameters(period).gov.ssa.ssi.eligibility.resources.limit + return person("ia_ssa_nonfinancial_eligible", period) & ( + resource <= where(couple, limit.couple, limit.individual) ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py index 835bf3253da..dd096f40aeb 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py @@ -11,7 +11,10 @@ class ia_ssa_federal(Variable): definition_period = MONTH unit = USD reference = ( - "https://hhs.iowa.gov/media/3987/download?inline=", + # 441 IAC 52.1(1), (2) and (4) + "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", + # PDF pages 20, 24-28, 30, 34-35 + "https://hhs.iowa.gov/media/3987/download?inline=#page=20", "https://secure.ssa.gov/poms.nsf/lnx/0501415058#f", ) defined_for = "ia_ssa_eligible" @@ -21,6 +24,9 @@ def formula(person, period, parameters): ssi = parameters(period).gov.ssa.ssi category = person("ia_ssa_category", period) c = category.possible_values + # NOTE: The joint-couple test uses the federal definition, which treats + # an aged, blind or disabled spouse who is ineligible for SSI or does + # not apply as part of a joint claim (issue 10138). joint = person("ssi_couple_computation_applies", period) blind = person("is_blind", period.this_year) blind_count = person.marital_unit.sum(blind) @@ -41,27 +47,46 @@ def formula(person, period, parameters): ) + p.dependent_amount ) + # NOTE: 6-B p.24 excludes as a dependent "A person whose countable + # income is more than $518 per month", which would admit income of + # exactly $518. 6-B p.25 ("The dependent must have countable income of + # less than $518 per month") and 441 IAC 51.5(1) ("must be less than + # the amount established by the department") exclude it. The model + # follows 51.5(1) and p.25 (ia_ssa.yaml Case 6). dp = ( (category == c.DEPENDENT_PERSON) & (dependent < p.dependent_amount) & (group_income < need) ) + # 6-B: the family-life home standard is "$1,156", and the maximum + # supplement is "$162 ($1,156 - $994 SSI standard)". SSA pays at most + # $142 because it applies the $20 general exclusion. The couple amount + # is twice the standard less the SSI couple rate and $20 (POMS code D + # Aged/Aged $801), so the standard and the couple amount move with the + # federal benefit rate. + general = ssi.income.exclusions.general + family_life_need = ssi.amount.individual + p.family_life_supplement flh = (category == c.FAMILY_LIFE_HOME) & ( - person("ia_ssa_care_countable_income", period) < p.family_life_need + person("ia_ssa_care_countable_income", period) < family_life_need ) + family_life_individual = p.family_life_supplement - general + family_life_couple = 2 * family_life_need - ssi.amount.couple - general federal_la = person("ssi_federal_living_arrangement", period) medical = federal_la == federal_la.possible_values.MEDICAL_TREATMENT_FACILITY individual_rate = ( dp * p.dependent_amount - + flh * p.family_life_individual_amount + + flh * family_life_individual + blind * p.blind_amount ) - # The state manual and SSA's category definition add $22 per blind - # spouse. The SSA table's mixed-category C rows show an inconsistent - # $44 increment; use the explicitly stated per-blind-person rule. + # NOTE: 6-B Income (DP) lists "Blind client, aged or disabled spouse, and + # a dependent relative $2,031", a $540 supplement over the $1,491 + # couple rate. POMS SI 01415.058 F.2.b code C shows Aged/Blind 562.00 + # (2,053.00), which is the blind/blind level. The model follows the + # manual and POMS F.1 code C ("increases by $22 for each blind + # recipient"), adding $22 per blind spouse (integration.yaml Case 4). couple_rate = ( dp * p.dependent_amount - + flh * p.family_life_couple_amount + + flh * family_life_couple + 2 * blind * p.blind_amount ) recipient = (individual_rate > 0) & ~medical & person("ia_ssa_eligible", period) @@ -77,6 +102,10 @@ def formula(person, period, parameters): # Only the blind member receives the ordinary categorical allowance. # DP/FLH couples share the combined payment without duplication. payment = where(joint, payment * 2 / max_(count, 1), payment) * recipient + # SSA pays these rows, so its rounding and $1 minimum apply. The helper + # would apply them before the redistribution above, so it returns the + # unrounded amount and the same SSA rule is applied here afterwards + # (SI 02001.005, SI 02001.010). rounded = np.ceil(np.floor(payment * 1000) / 10) / 100 return where( rounded > 0, max_(rounded, ssi.state_supplement.minimum_payment), 0 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py new file mode 100644 index 00000000000..13f2b48274f --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py @@ -0,0 +1,38 @@ +from policyengine_us.model_api import * + + +class ia_ssa_ihhrc_amount(Variable): + value_type = float + entity = Person + label = "Iowa SSA in-home health-related care amount before non-income eligibility" + definition_period = MONTH + unit = USD + defined_for = StateCode.IA + reference = ( + # 441 IAC 177.8(2) + "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=4", + # PDF pages 41-42 + "https://hhs.iowa.gov/media/3987/download?inline=#page=41", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ia.hhs.ssa + category = person("ia_ssa_category", period) + home = category == category.possible_values.IN_HOME_CARE + cost = max_(person("ia_ssa_ihhrc_monthly_cost", period), 0) + # Care costing more than the monthly ceiling is ineligible, not capped. + approved = home & (cost <= p.ihhrc_cost_limit) + partial = person("ia_ssa_care_partial_month_days", period) + days = where(partial > 0, min_(partial, period.days), period.days) + covered_cost = cost * days / period.days * approved + total_cost = person.marital_unit.sum(covered_cost) + payable = max_(total_cost - person("ia_ssa_ihhrc_participation", period), 0) + # Allocate a common household contribution proportionately to the + # approved costs, preserving the household's total payable benefit. + share = np.divide( + covered_cost, + total_cost, + out=np.zeros_like(covered_cost), + where=total_cost > 0, + ) + return payable * share diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_initial_partial_month.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_initial_partial_month.py index 8f120c9e425..55ff91a3dfd 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_initial_partial_month.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_initial_partial_month.py @@ -6,4 +6,15 @@ class ia_ssa_ihhrc_initial_partial_month(Variable): entity = Person label = "Iowa IHHRC initial partial month without client participation" definition_period = MONTH - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) + defined_for = StateCode.IA + default_value = False + documentation = "Set only for a first month of in-home health-related care service that is less than a full month, when no client participation is required. Key the entry to its month and enter the covered days in ia_ssa_care_partial_month_days." + reference = ( + "https://hhs.iowa.gov/media/3987/download?inline=#page=42", + # 441 IAC 177.8(2)"b" + "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=4", + ) + + def formula(person, period, parameters): + # A formula stops a one-month input from carrying into later months. + return False diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py index a27ecd80312..526daa54451 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py @@ -7,5 +7,5 @@ class ia_ssa_ihhrc_monthly_cost(Variable): label = "Iowa SSA approved monthly in-home health-related care cost" definition_period = MONTH unit = USD - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) - documentation = "Cost of the approved full-month service plan per recipient; care costing above the monthly ceiling is ineligible rather than capped." + reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=41" + documentation = "Cost of the approved full-month service plan per recipient; care costing above the monthly ceiling is ineligible rather than capped. An entry carries into later months until it is changed." diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py new file mode 100644 index 00000000000..93fc47de7cc --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py @@ -0,0 +1,35 @@ +from policyengine_us.model_api import * + + +class ia_ssa_ihhrc_participation(Variable): + value_type = float + entity = Person + label = "Iowa SSA in-home health-related care client participation" + definition_period = MONTH + unit = USD + defined_for = StateCode.IA + reference = ( + # 441 IAC 177.2(1)"f"-"g" and 177.8(2) + "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=1", + # PDF pages 41-43, 49 + "https://hhs.iowa.gov/media/3987/download?inline=#page=41", + ) + + def formula(person, period, parameters): + # 6-B Home Maintenance Allowance (IHHRC) prints the SSI individual and + # couple standards ($994 and $1,491) and gives the couple allowance + # "even if only one spouse receives in-home health-related care", so + # the federal benefit rates are used and an SSI reform carries over. + # A child's marital unit has one member and receives the individual + # standard. + ssi = parameters(period).gov.ssa.ssi + income = person("ia_ssa_care_countable_income", period) + deductions = max_(person("ia_ssa_care_additional_deductions", period), 0) + has_spouse = person.marital_unit.nb_persons() == 2 + maintenance = where(has_spouse, ssi.amount.couple, ssi.amount.individual) + deductions = where(has_spouse, person.marital_unit.sum(deductions), deductions) + participation = max_(income - maintenance - deductions, 0) + # No client participation is required in a first partial month. + return where( + person("ia_ssa_ihhrc_initial_partial_month", period), 0, participation + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.py new file mode 100644 index 00000000000..fc723ddf75e --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.py @@ -0,0 +1,88 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.ssa.ssi.eligibility.resources.deemed.ssi_resources_deemed_from_ineligible_parent import ( + _ssi_parental_resource_pool, +) + + +class ia_ssa_income_deemed_from_parents(Variable): + value_type = float + entity = Person + label = "Iowa SSA in-home health-related care income deemed from parents" + definition_period = MONTH + unit = USD + defined_for = StateCode.IA + reference = ( + # PDF pages 46-49 + "https://hhs.iowa.gov/media/3987/download?inline=#page=46", + # 441 IAC 177.2(1)"g"(1) + "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=2", + ) + + def formula(person, period, parameters): + # 6-B: "The procedures for deeming from a parent to a child under + # in-home health-related care differ from the SSI program", so the + # Iowa method replaces SSI parental income deeming for these children. + # The deemors are the co-resident parents and each parent's + # co-resident spouse, as for parental resources; a parent who receives + # SSI is not a deemor. + # NOTE: The manual and the rule it cites deduct the unmet medical needs + # of the parents and ineligible children, which are not modeled. + # NOTE: 6-B p.47: "For parents with earned income only, allow the + # following deductions before deeming income to the eligible child: $65 + # work expense. Double the SSI allowance". 441 IAC 177 lists only "an + # additional basic SSI standard" when all income is earned, with no $65: + # 177.4(1)"g"(1) in the IAC 2/5/25 edition and 177.2(1)"g"(1) after ARC + # 0460D (IAC 8/5/26, effective October 1, 2026), so the conflict covers + # all of 2026. The model follows the manual + # (ia_ssa_income_deemed_from_parents.yaml Cases 2-3). + ssi = parameters(period).gov.ssa.ssi + receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) + earned = where(receives_ssi, 0, person("ssi_earned_income", period)) + unearned = where(receives_ssi, 0, person("ssi_unearned_income", period)) + parental_earned, parent_count, pool = _ssi_parental_resource_pool( + person, period, earned + ) + parental_unearned, _, _ = _ssi_parental_resource_pool(person, period, unearned) + # 6-B, Home Maintenance Allowance (IHHRC): the 6-B allowances equal the + # SSI individual, couple and dependent standards, so an SSI reform + # carries over to Iowa. + # NOTE: As in resources deeming, the allowance follows the number of + # co-resident deemors including a parent who receives SSI, so one SSI + # parent with an ineligible parent gives the couple allowance. Federal + # ssi_ineligible_parent_allocation counts only ineligible parents; 6-B + # and 441 IAC 177 are silent on this case. + allowance = where(parent_count > 1, ssi.amount.couple, ssi.amount.individual) + pool_count = int(np.max(pool, initial=-1)) + 1 + # Each ineligible child of the same parents adds the SSI dependent + # standard less that child's own income. + sibling_allowance = np.bincount( + pool, + weights=person("ssi_ineligible_child_allocation", period), + minlength=pool_count, + )[pool] + exclusions = ssi.income.exclusions + has_earned = parental_earned > 0 + has_unearned = parental_unearned > 0 + remaining_earned = max_(parental_earned - exclusions.earned, 0) + # All earned: $65 and a second SSI standard for the parents. Earned and + # unearned: $65 plus one-half of the remaining earnings. All unearned: + # no earnings deduction. + countable = select( + [has_earned & has_unearned, has_earned], + [ + remaining_earned * (1 - exclusions.earned_share) + parental_unearned, + remaining_earned - allowance, + ], + default=parental_unearned, + ) + deemed = max_(countable - allowance - sibling_allowance, 0) + # The Iowa sources are silent on several eligible children; divide + # equally among the blind or disabled children of the same parents, as + # SSI does. + eligible_child = person("is_ssi_aged_blind_disabled", period.this_year) & ( + person("is_child", period.this_year) + ) + children = np.bincount( + pool, weights=eligible_child.astype(float), minlength=pool_count + )[pool] + return eligible_child * deemed / max_(children, 1) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py new file mode 100644 index 00000000000..d91d540494d --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py @@ -0,0 +1,39 @@ +from policyengine_us.model_api import * + + +class ia_ssa_nonfinancial_eligible(Variable): + value_type = bool + entity = Person + label = "Iowa SSA nonfinancial eligibility" + definition_period = MONTH + defined_for = StateCode.IA + reference = ( + # Iowa Code 249.3 + "https://www.legis.iowa.gov/docs/code/249.pdf#page=1", + # PDF pages 6, 8, 10-12 + "https://hhs.iowa.gov/media/3987/download?inline=#page=6", + ) + + def formula(person, period, parameters): + category = person("ia_ssa_category", period) + immigration = person("immigration_status", period.this_year) + citizen = immigration == immigration.possible_values.CITIZEN + immigrant = person("is_ssi_qualified_noncitizen", period.this_year) + # 6-B Nonfinancial Eligibility: applicants "must also apply for SSI or + # FIP if they might be eligible". An applicant whose income would + # qualify for SSI must take it up; one over income for SSI need not. + pursues_ssi = person("takes_up_ssi_if_eligible", period.this_year) | ( + person("uncapped_ssi", period) <= 0 + ) + # NOTE: The SMME exception for a disabled person engaged in substantial + # gainful activity (Iowa Code 249.3(4)(a)(2); 441 IAC 51.7(2); 6-B p.10: + # "an applicant must meet disability standards other than the inability + # to engage in substantial gainful activity") is not modeled, because + # is_ssi_disabled excludes people working above the SGA level. + return ( + person("is_ssi_aged_blind_disabled", period.this_year) + & (citizen | immigrant) + & (category != category.possible_values.NONE) + & ~person("is_incarcerated", period) + & pursues_ssi + ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_daily_rate.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_daily_rate.py index 768f091f40a..dccd18794b3 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_daily_rate.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_daily_rate.py @@ -7,4 +7,5 @@ class ia_ssa_rcf_daily_rate(Variable): label = "Iowa SSA approved residential care daily rate" definition_period = MONTH unit = USD - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) + reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=72" + documentation = "The per diem rate the department established for the facility; the model caps it at the maximum cost-related rate. Leave at 0 when no rate is approved. An entry carries into later months until it is changed." diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py index be740f5788f..56ccba3f7d8 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py @@ -1,7 +1,6 @@ from policyengine_us.model_api import * -from policyengine_us.variables.gov.states._ssp_parental_resources import ( - ssp_parental_resources, - ssp_sibling_resource_share, +from policyengine_us.variables.gov.ssa.ssi.eligibility.resources.deemed.ssi_resources_deemed_from_ineligible_parent import ( + _ssi_parental_resource_pool, ) @@ -14,70 +13,56 @@ class ia_ssa_resources_deemed_from_parents(Variable): unit = USD defined_for = StateCode.IA reference = ( - "https://hhs.iowa.gov/media/3987/download?inline=#page=46", - "https://www.law.cornell.edu/cfr/text/20/416.1202", - "https://www.law.cornell.edu/cfr/text/20/416.1856", + # PDF pages 12, 46-47 + "https://hhs.iowa.gov/media/3987/download?inline=#page=12", + "https://www.ecfr.gov/current/title-20/section-416.1202#p-416.1202(b)", + "https://www.ecfr.gov/current/title-20/section-416.1856", "https://secure.ssa.gov/poms.nsf/lnx/0501330200", "https://secure.ssa.gov/poms.nsf/lnx/0501330280", "https://secure.ssa.gov/poms.nsf/lnx/0501330310", "https://secure.ssa.gov/poms.nsf/lnx/0501330340", ) - # Calculated from co-resident parent links and SSI countable assets, with the - # one/two-parent allowance and eligible-child allocation. Actual SSI receipt or - # otherwise-eligible IHHRC determines the ordinary allocation pool. Override with - # the agency-determined amount for a deeming exception, a step-only household, other - # state-only sibling eligibility, or a different certified resource budget. Supply - # each affected child's amount when its allocation pool differs. Parents receiving - # SSI are not resource deemors; other public-assistance income exclusions do not by - # themselves exclude resources. Parent links must identify all co-resident parents. - # The allowance follows the number of co-resident parents, including an - # SSI-recipient parent. The cited rules do not explicitly resolve this allowance - # interaction for unmarried parents with mixed SSI status; use an agency-determined - # deemed-resource input for such a budget. + # 6-B deems parental resources above the $2,000 one-parent or $3,000 + # two-parent allowance "in the same manner as SSI policy"; these equal the + # SSI limits, so the federal parameters are used. The deemors are + # the co-resident parents named by parent links (or the unlinked-parent + # proxy) plus each parent's co-resident spouse, as in SSI's + # 416.1202(b)(1) pool, so a stepparent's resources are deemed. Parents + # receiving SSI are not resource deemors, but the allowance follows the + # number of co-resident deemors including them. The excess is divided + # among the children of the same deemors who receive SSI or would + # otherwise receive in-home health-related care, removing any child whose + # own resources plus the share exceed the limit (SI 01330.200 and .280). + # Certified deeming exceptions and other state-only sibling eligibility + # are not modeled. def formula(person, period, parameters): - first, second, excess = ssp_parental_resources( - person, period, parameters, exclude_ssi_parents=True + limit = parameters(period).gov.ssa.ssi.eligibility.resources.limit + receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) + resources = where(receives_ssi, 0, person("ssi_resources_for_deeming", period)) + parental_resources, parent_count, pool = _ssi_parental_resource_pool( + person, period, resources ) - p = parameters(period).gov.states.ia.hhs.ssa - federal = parameters(period).gov.ssa.ssi + allowance = where(parent_count > 1, limit.couple, limit.individual) + excess = max_(parental_resources - allowance, 0) child = ( person("is_child", period.this_year) & (person.marital_unit.nb_persons() == 1) & ~person("is_household_head", period.this_year) ) - category = person("ia_ssa_category", period) - home = category == category.possible_values.IN_HOME_CARE - immigration = person("immigration_status", period.this_year) - immigration_eligible = ( - immigration == immigration.possible_values.CITIZEN - ) | person("is_ssi_qualified_noncitizen", period.this_year) - cost = max_(person("ia_ssa_ihhrc_monthly_cost", period), 0) - income = person("ia_ssa_care_countable_income", period) - deductions = max_(person("ia_ssa_care_additional_deductions", period), 0) - participation = max_(income - federal.amount.individual - deductions, 0) - participation = where( - person("ia_ssa_ihhrc_initial_partial_month", period), 0, participation + ihhrc = person("ia_ssa_nonfinancial_eligible", period) & ( + person("ia_ssa_ihhrc_amount", period) > 0 ) - days = clip(person("ia_ssa_care_days", period), 0, period.days) - ihhrc = ( - home - & person("is_ssi_aged_blind_disabled", period.this_year) - & immigration_eligible - & person("takes_up_ssi_if_eligible", period.this_year) - & ~person("is_incarcerated", period) - & (cost <= p.ihhrc_cost_limit) - & (cost * days / period.days > participation) - ) - candidates = child & ((person("ssi", period) > 0) | ihhrc) own = person("ssi_countable_resources", period.this_year) - share = ssp_sibling_resource_share( - person, - first, - second, - excess, - candidates, - own, - federal.eligibility.resources.limit.individual, - ) + eligible = child & (receives_ssi | ihhrc) & (own <= limit.individual) + pool_count = int(np.max(pool, initial=-1)) + 1 + share = excess + # Each round removes at least one child or leaves the result stable. + for _ in range(int(np.max(person.household.nb_persons(), initial=0)) + 1): + count = np.bincount(pool[eligible], minlength=pool_count) + share = excess / max_(count[pool], 1) + remaining = eligible & (own + share <= limit.individual) + if np.array_equal(remaining, eligible): + break + eligible = remaining return child * share diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py index 2c044b6ac13..e57b4480ffe 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py @@ -7,8 +7,9 @@ class ia_ssa_smme_countable_income(Variable): label = "Iowa SMME countable income for Medicaid coverage group" definition_period = MONTH unit = USD - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) - documentation = "Override with income calculated using the deductions and financial group of the actual Medicaid coverage category when these differ from SSI." + defined_for = StateCode.IA + documentation = "SSI countable income plus any SSI payment. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." + reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=77" def formula(person, period, parameters): return person("ssi_countable_income", period) + person("ssi", period) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_coverage_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_coverage_eligible.py index 72a9f26656c..a729e614e02 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_coverage_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_coverage_eligible.py @@ -6,5 +6,5 @@ class ia_ssa_smme_coverage_eligible(Variable): entity = Person label = "Iowa SMME full Medicaid and Medicare Part B requirements met" definition_period = MONTH - reference = ("https://hhs.iowa.gov/media/3987/download?inline=",) + reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=76" documentation = "Receiving full Medicaid under a category independent of SSA without a premium or spenddown, and eligible for Medicare Part B. Ordinary Medicaid enrollment alone does not establish this status." 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 9873de52c63..de55c6a583d 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 @@ -26,7 +26,7 @@ def formula(spm_unit, period, parameters): "pa_ssp", # Pennsylvania benefits "wy_ssp", # Wyoming benefits "nc_sa", # North Carolina benefits - "ia_ssa", + "ia_ssa", # Iowa benefits "ks_sspp", # Kansas benefits "hi_oss", "la_oss", # Louisiana benefits From 0231a5751bda1dc9d74d45a651813ce7d249f1c2 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 20 Oct 2026 18:12:15 -0400 Subject: [PATCH 26/33] Address David's and Pavel's reviews of Iowa State Supplementary Assistance - SMME tests an eligible couple's combined income against the couple guideline. - In-home care deducts the dependent child allowance; residential care defaults to the maximum per diem, shields income up to the SSI rate in the entry month, and budgets spouses as individuals after the entry month. - The residential care personal needs allowance rises with the SSI COLA (Iowa Code 249.9A(1)). - Interest and dividends are excluded consistently (20 CFR 416.1124(c)(22)). - The spouse test uses SSI's spouse definition, and SSA's resource-deeming finding stands for SSI children. - Certifying either spouse applies the dependent-person couple level. - New source-conflict NOTEs, page anchors, defaults and boundary tests; child_support_share.yaml is left as on main (issue 10242). Co-Authored-By: Claude Opus 5.5 --- .../ia/hhs/ssa/excluded_unearned_sources.yaml | 18 + .../ia/hhs/ssa/family_life_supplement.yaml | 4 +- .../states/ia/hhs/ssa/ihhrc_cost_limit.yaml | 22 +- .../states/ia/hhs/ssa/rcf_daily_limit.yaml | 10 +- .../states/ia/hhs/ssa/rcf_personal_needs.yaml | 18 +- .../ia/hhs/ssa/smme_minimum_fpg_rate.yaml | 4 + policyengine_us/programs.yaml | 5 +- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 1139 ++++++++++++++++- .../gov/states/ia/hhs/ssa/integration.yaml | 88 ++ .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 66 +- .../ssa/ia_ssa_care_additional_deductions.py | 4 +- .../hhs/ssa/ia_ssa_care_countable_income.py | 71 +- .../ssa/ia_ssa_care_initial_partial_month.py | 25 + .../gov/states/ia/hhs/ssa/ia_ssa_category.py | 10 +- .../ssa/ia_ssa_dependent_countable_income.py | 1 + .../gov/states/ia/hhs/ssa/ia_ssa_eligible.py | 26 +- .../gov/states/ia/hhs/ssa/ia_ssa_federal.py | 29 +- .../states/ia/hhs/ssa/ia_ssa_has_spouse.py | 26 + .../states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py | 11 +- .../ssa/ia_ssa_ihhrc_initial_partial_month.py | 20 - .../ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py | 1 + .../ia/hhs/ssa/ia_ssa_ihhrc_participation.py | 36 +- .../ssa/ia_ssa_income_deemed_from_parents.py | 9 + .../hhs/ssa/ia_ssa_nonfinancial_eligible.py | 12 +- .../ia/hhs/ssa/ia_ssa_rcf_couple_budget.py | 45 + .../ia/hhs/ssa/ia_ssa_rcf_daily_rate.py | 9 +- .../ia_ssa_resources_deemed_from_parents.py | 21 +- .../hhs/ssa/ia_ssa_smme_countable_income.py | 23 +- .../hhs/ssa/ia_ssa_smme_coverage_eligible.py | 1 + 29 files changed, 1633 insertions(+), 121 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/excluded_unearned_sources.yaml create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_initial_partial_month.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_has_spouse.py delete mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_initial_partial_month.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_couple_budget.py diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/excluded_unearned_sources.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/excluded_unearned_sources.yaml new file mode 100644 index 00000000000..67f1105a653 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/excluded_unearned_sources.yaml @@ -0,0 +1,18 @@ +description: Iowa excludes these unearned income sources from countable income under the State Supplementary Assistance program. +values: + 2026-01-01: + - interest_income + - dividend_income + +metadata: + unit: list + period: year + label: Iowa SSA excluded unearned income sources + # NOTE: 20 CFR 416.1124(c)(22) excludes interest and dividends from a + # countable resource, but federal SSI in the model still counts them (issue + # 10079). Remove this list once SSI excludes them, or they are excluded twice. + reference: + - title: 20 CFR 416.1124(c)(22) + href: https://www.ecfr.gov/current/title-20/section-416.1124#p-416.1124(c)(22) + - title: "Iowa HHS Employees' Manual 8-E (revised April 11, 2025), Dividends and Interest Income #page 23,36" + href: https://hhs.iowa.gov/media/4011/download?inline#page=23 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_supplement.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_supplement.yaml index 16a9bd986db..67de08f57bb 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_supplement.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/family_life_supplement.yaml @@ -11,8 +11,8 @@ metadata: # this supplement less the $20 general exclusion. The couple amount is twice # the standard less the SSI couple rate and $20 (POMS code D Aged/Aged $801). reference: - - title: "Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Family-Life Home Supplement #page 30,34-35" - href: https://hhs.iowa.gov/media/3987/download?inline=#page=30 + - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Making the Family-Life Home Payment + href: https://hhs.iowa.gov/media/3987/download?inline=#page=35 - title: 441 IAC 52.1 and 52.1(1) href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 - title: SSA POMS SI 01415.058 F.2 (TN 95, 08-26), Iowa code D payment levels diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml index 2d78ce3b09d..2af36c45eeb 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml @@ -6,17 +6,21 @@ metadata: unit: currency-USD period: month label: Iowa SSA maximum in-home health-related care cost per recipient - # NOTE: 6-B Income (IHHRC) p.41: "If the care needed by the client is more + # 6-B Income (IHHRC) p.41: "If the care needed by the client is more # expensive than these limits, the client is not eligible for a SSA payment - # for in-home health-related care." 441 IAC 177 instead limits countable - # income to "$480.55 per month if one needs care or $961.10 if both need care" - # and pays "the reasonable charges for such services up to and including - # $480.55". The IAC 2/5/25 edition has this text at 177.4(1)"f" and 177.10(3) - # (pages 2 and 5), and ARC 0460D (IAC 8/5/26, effective October 1, 2026) keeps - # it at 177.2(1)"f" and 177.8(3) (pages 1 and 4), so the conflict covers all - # of 2026. The model follows the manual (ia_ssa.yaml Cases 22-23). + # for in-home health-related care." 441 IAC 177 agrees: 177.9(4) (IAC + # 8/5/26, ARC 0460D, effective October 1, 2026) terminates IHHRC for + # "Excessive costs. When the cost of care exceeds the maximum established in + # subrule 177.9(3)", a cross-reference that should read 177.8(3), the + # $480.55 maximum benefit payable. The IAC 2/5/25 edition has it at + # 177.11(4), citing 177.10(3). 177.2(1)"f" also limits countable income to + # "$480.55 per month if one needs care or $961.10 if both need care", which + # pays nothing whenever participation reaches the cost (ia_ssa.yaml Cases + # 22-23). reference: - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Income (IHHRC) href: https://hhs.iowa.gov/media/3987/download?inline=#page=41 - - title: '441 IAC 177.2(1)"f" and 177.8(3) (IAB 8/5/26) #page 1,4' + - title: '441 IAC 177.2(1)"f", 177.8(3) and 177.9(4) (IAC 8/5/26) #page 1,4-5' href: https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=1 + - title: '441 IAC 177.4(1)"f", 177.10(3) and 177.11(4) (IAC 2/5/25) #page 2,5' + href: https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml index 2621c2ca709..6d874652e40 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml @@ -6,11 +6,15 @@ metadata: unit: currency-USD period: day label: Iowa SSA maximum residential care daily rate - # NOTE: 441 IAC 52.1 adjusts assistance standards each January 1 for the SSA - # cost-of-living adjustment but publishes no method, so this value stays at - # its 2026 level until a later schedule is added. + # NOTE: Iowa Code 249.12(3) sets the rate through "the maximum per diem rates + # established by the general assembly through the appropriations process", + # not by the COLA (2025 $37.60 to 2026 $38.47 is 2.3 percent against a 2.8 + # percent COLA). Later years carry the 2026 rate as a frozen projection until + # a new rate is published. reference: - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Billing and Payments (RCF) href: https://hhs.iowa.gov/media/3987/download?inline=#page=72 - title: "441 IAC 52.1 and 52.1(3) #page 1-2" href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 + - title: Iowa Code 249.12(3) + href: https://www.legis.iowa.gov/docs/code/249.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml index 9ca63d6130b..8e5aa9f405d 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml @@ -6,11 +6,23 @@ metadata: unit: currency-USD period: month label: Iowa SSA residential care personal needs allowance - # NOTE: 441 IAC 52.1 adjusts assistance standards each January 1 for the SSA - # cost-of-living adjustment but publishes no method, so this value stays at - # its 2026 level until a later schedule is added. + # Iowa Code 249.9A(1): the department "shall increase the personal needs + # allowance for residents of residential care facilities by the same + # percentage and at the same time as federal supplemental security income and + # federal social security benefits are increased due to a recognized increase + # in the cost of living". Rounding to the nearest dollar is inferred from + # General Letters 6-B-45, 6-B-46 and 6-B-47 ($123, $126 and $130 for + # 2024-2026: 123 * 1.025 = 126.08 and 126 * 1.028 = 129.53). The published + # allowance replaces the projection. + uprating: + parameter: gov.ssa.uprating + rounding: + type: nearest + interval: 1 reference: - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Personal Needs Allowance (RCF) href: https://hhs.iowa.gov/media/3987/download?inline=#page=62 - title: 441 IAC 52.1 and 52.1(3)"a"(2) href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 + - title: Iowa Code 249.9A(1) + href: https://www.legis.iowa.gov/docs/code/249.pdf#page=4 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml index 14362cc9d80..d54bb93c13f 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/smme_minimum_fpg_rate.yaml @@ -9,3 +9,7 @@ metadata: reference: - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Income (SMME) href: https://hhs.iowa.gov/media/3987/download?inline=#page=77 + - title: 441 IAC 51.7(6) + href: https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=2 + - title: "Iowa Code 249.3(4)(g) #page 2-3" + href: https://www.legis.iowa.gov/docs/code/249.pdf#page=2 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 3087dbb91e3..2be8f0b7531 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1002,8 +1002,9 @@ programs: notes: >- Models 2026 blind, dependent-person, family-life home, residential care, in-home health-related care and SMME supplements; special - categories need certification inputs. Mandatory minimum-income-level - and conditional-benefit payments are not modeled. + categories need certification inputs, so microsimulation pays only + the blind supplement. Mandatory minimum-income-level and + conditional-benefit payments are not modeled. - 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 35316be759d..121c10b7d3a 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 @@ -21,7 +21,7 @@ output: ia_ssa: 22 -- name: Case 3, blind state-only income gap. +- name: Case 3, the Social Security Administration pays the blind supplement without federal SSI. period: 2026-01 absolute_error_margin: 0.01 input: @@ -32,6 +32,7 @@ is_blind: true social_security_retirement: 12_240 output: + # SSI: 1,020 - 20 = 1,000 > 994, so SSI is 0; 994 + 22 - 1,000 = 16. ia_ssa: 16 - name: Case 4, dependent-person supplement. @@ -150,7 +151,7 @@ output: ia_ssa: 142 -- name: Case 13, state-only family-life payment. +- name: Case 13, the Social Security Administration pays the family-life home supplement without federal SSI. period: 2026-01 absolute_error_margin: 0.01 input: @@ -161,6 +162,8 @@ ia_ssa_category: FAMILY_LIFE_HOME social_security_retirement: 13_200 output: + # SSI: 1,100 - 20 = 1,080 > 994, so SSI is 0. Care income 1,100 is below + # 1,156, so SSA pays 142 - (1,080 - 994) = 56. ia_ssa: 56 - name: Case 14, RCF actual January cost less participation. @@ -187,6 +190,7 @@ ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 38.47 output: + # February 2026 has 28 days: 38.47 * 28 = 1,077.16; 1,077.16 - 864 = 213.16. ia_ssa: 213.16 - name: Case 16, blind RCF resident also gets blind supplement. @@ -244,7 +248,7 @@ output: ia_ssa: 328.57 -- name: Case 20, RCF requires a facility rate. +- name: Case 20, RCF without a facility rate is paid at the maximum daily rate. period: 2026-01 absolute_error_margin: 0.01 input: @@ -254,7 +258,10 @@ 2026: 65 ia_ssa_category: RESIDENTIAL_CARE output: - ia_ssa: 0 + # 441 IAC 52.1(3): payment "will be based on the maximum per diem rate". + # 38.47 * 31 = 1,192.57; SSI 994, participation 994 - 130 = 864; + # 1,192.57 - 864 = 328.57. + ia_ssa: 328.57 - name: Case 21, in-home care at approved cost. period: 2026-01 @@ -338,9 +345,10 @@ ia_ssa_ihhrc_monthly_cost: 400 social_security_retirement: 16_800 ia_ssa_care_partial_month_days: 16 - ia_ssa_ihhrc_initial_partial_month: true + ia_ssa_care_initial_partial_month: true output: - ia_ssa: 206.4516129032258 + # No participation in the first partial month: 400 * 16 / 31 = 206.45. + ia_ssa: 206.45 - name: Case 27, blind allowance coexists with in-home care. period: 2026-01 @@ -914,16 +922,20 @@ child1: members: [person2] families: - family: - members: [person1, person2] + parent_family: + members: [person1] + child_family: + members: [person2] tax_units: parent1: members: [person1] child1: members: [person2] spm_units: - unit: - members: [person1, person2] + parent_unit: + members: [person1] + child_unit: + members: [person2] households: parent_home: members: [person1] @@ -949,7 +961,7 @@ ia_ssa_category: IN_HOME_CARE ia_ssa_ihhrc_monthly_cost: 400 ia_ssa_care_partial_month_days: 16 - ia_ssa_ihhrc_initial_partial_month: true + ia_ssa_care_initial_partial_month: true person2: age: 2026: 65 @@ -995,7 +1007,8 @@ 2026: 65 ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 38.47 - # Entry on January 7: the day of entry through January 31. + # Discharged January 26: January 1 through 25; the day of discharge is + # not paid (441 IAC 52.1(3)"b"). ia_ssa_care_partial_month_days: 25 person2: age: @@ -1042,12 +1055,12 @@ 2026-02: 400 ia_ssa_care_partial_month_days: 2026-01: 16 - ia_ssa_ihhrc_initial_partial_month: + ia_ssa_care_initial_partial_month: 2026-01: true output: # January: no participation; 400 * 16 / 31 = 206.45. # February: participation 1,400 - 994 = 406 is at least the 400 cost. - ia_ssa_ihhrc_initial_partial_month: + ia_ssa_care_initial_partial_month: 2026-01: true 2026-02: false ia_ssa_care_partial_month_days: @@ -1150,7 +1163,7 @@ output: ia_ssa: 22 -- name: Case 52, 2027 residential care participation uses the 2027 SSI rate. +- name: Case 52, 2027 residential care participation uses the 2027 SSI rate and personal needs allowance. period: 2027-01 absolute_error_margin: 0.01 input: @@ -1161,8 +1174,11 @@ ia_ssa_category: RESIDENTIAL_CARE ia_ssa_rcf_daily_rate: 38.47 output: - # SSI 1,029; participation 1,029 - 130 = 899; 38.47 * 31 = 1,192.57 - 899 = 293.57. - ia_ssa: 293.57 + # Iowa Code 249.9A(1) raises the personal needs allowance by the SSI + # cost-of-living percentage: 130 * 328.746 / 317.265 = 134.70, rounded to + # 135. SSI 1,029; participation 1,029 - 135 = 894; the 2026 maximum rate is + # carried forward: 38.47 * 31 = 1,192.57 - 894 = 298.57. + ia_ssa: 298.57 - name: Case 53, 2027 family-life home standard follows the SSI rate. period: 2027-01 @@ -1190,7 +1206,10 @@ ia_ssa_category: FAMILY_LIFE_HOME ia_ssa_care_countable_income: 1_191 output: - # Income must be below the 1,029 + 162 = 1,191 standard. + # 6-B p.34: countable income "must not be more than" the standard, + # 1,029 + 162 = 1,191. The model admits only income below it; with real + # income at the standard, SSA's payment is 142 - (1,171 - 1,029) = 0 + # either way. ia_ssa_federal: 0 - name: Case 55, negative self-employment income does not inflate the residential care payment. @@ -1285,7 +1304,1091 @@ output: # SSI countable income 1,500 - 20 = 1,480 exceeds 994, so SSI is 0. # Iowa: 1,500 - 500 one-third exclusion = 1,000; participation 1,000 - 994 = 6. + # Federal SSI does not yet apply 20 CFR 416.1124(c)(11) (issue 10242). Once + # it does, SSI is 994 - (1,000 - 20) = 14, participation + # 1,000 + 14 - 994 = 20 and ia_ssa 380. ssi: [0, 0] ia_ssa_care_countable_income: [0, 1_000] ia_ssa_ihhrc_participation: [0, 6] ia_ssa: [0, 394] + +# 441 IAC 51.7(6) and 6-B Income (SMME) p.77: income "must exceed 120 percent +# of the federal poverty level". Case 59 is an aged couple with Social Security +# of $1,700 a month each; Cases 60-61 bracket the two-person threshold of +# 1.2 * (15,960 + 5,680) / 12 = 2,164. +- name: Case 59, an SMME couple's combined income is compared with the two-person guideline. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + social_security_retirement: + 2026: 20_400 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 70 + social_security_retirement: + 2026: 20_400 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # Both spouses are aged, so SSI budgets them as a couple: + # 1,700 + 1,700 - 20 = 3,380 > 1,491, so SSI is 0, and SSI countable + # income is 3,380 / 2 = 1,690 each. + # SMME income combines the couple: 1,690 + 1,690 = 3,380 > 2,164, so each + # covered spouse gets $1. (Half the couple's income, 1,690, would fail.) + ssi_couple_computation_applies: [true, true] + ssi_countable_income: [1_690, 1_690] + ssi: [0, 0] + ia_ssa_smme_countable_income: [3_380, 3_380] + ia_ssa_federal: [0, 0] + ia_ssa: [1, 1] + +- name: Case 60, an SMME couple just above the two-person guideline with one spouse covered. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + # Boundary income: $1,093 a month each puts the couple $2 above the + # 2,164 threshold. + social_security_retirement: + 2026: 13_116 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 70 + social_security_retirement: + 2026: 13_116 + ia_ssa_category: SMME + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # SSI: 1,093 + 1,093 - 20 = 2,166 > 1,491, so SSI is 0; 2,166 / 2 = 1,083 + # each. SMME income 1,083 + 1,083 = 2,166 > 2,164. + # Only person1 has the Medicaid and Part B coverage, so only person1 is + # paid. Each spouse's own 1,093 - 20 = 1,073 is below the one-person + # 1,596, so this case pins the combined reading. + ssi_countable_income: [1_083, 1_083] + ssi: [0, 0] + ia_ssa_smme_countable_income: [2_166, 2_166] + ia_ssa: [1, 0] + +- name: Case 61, an SMME couple just below the two-person guideline. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + # Boundary income: $1,091 a month each puts the couple $2 below the + # 2,164 threshold. + social_security_retirement: + 2026: 13_092 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 70 + social_security_retirement: + 2026: 13_092 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # SSI: 1,091 + 1,091 - 20 = 2,162 > 1,491, so SSI is 0; 2,162 / 2 = 1,081 + # each. SMME income 1,081 + 1,081 = 2,162 does not exceed 2,164. + ssi_countable_income: [1_081, 1_081] + ssi: [0, 0] + ia_ssa_smme_countable_income: [2_162, 2_162] + ia_ssa: [0, 0] + +# 441 IAC 177.2(1)"f"(3) and 6-B Home Maintenance Allowance (IHHRC) p.43, +# example 2: "Mr. B receives $1,400 in social security benefits; the child +# receives $125." +- name: Case 62, manual IHHRC example deducts the dependent allowance less the child's income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + social_security_retirement: + 2026: 16_800 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + person2: + age: + 2026: 10 + social_security_dependents: + 2026: 1_500 + marital_units: + parent: + members: [person1] + child: + members: [person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # SSI: 1,400 - 20 = 1,380 > 994, so SSI is 0. The child is not aged, + # blind or disabled. + # Dependent allowance: 497 (1,491 - 994) - 125 = 372. + # Participation: 1,400 - 994 - 372 = 34 (6-B p.43); 400 - 34 = 366. + ssi: [0, 0] + ssi_ineligible_child_allocation: [0, 372] + ia_ssa_care_countable_income: [1_400, 125] + ia_ssa_ihhrc_participation: [34, 0] + ia_ssa: [366, 0] + +# 6-B Client Participation for Adults (IHHRC) p.42: "The household consists +# of the recipient, the recipient's spouse, and two children. The spouse has +# earned income of $4,500." +- name: Case 63, manual IHHRC example with a working spouse and two children has no participation. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + person2: + age: + 2026: 40 + employment_income: + 2026: 54_000 + person3: + age: + 2026: 8 + person4: + age: + 2026: 5 + marital_units: + couple: + members: [person1, person2] + child1: + members: [person3] + child2: + members: [person4] + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: IA + output: + # SSI deems the spouse's 4,500 less 2 * 497 for the children, 3,506, which + # is above 497. (3,506 - 20 - 65) / 2 = 1,710.50 > 1,491, so SSI is 0. + # Care income: (4,500 - 65) / 2 = 2,217.50, the spouse's own earnings + # under the same exclusions. + # Participation: 2,217.50 - 1,491 = 726.50; 726.50 - 994 < 0, so 0 + # (6-B p.42), and the full 400 cost is paid. + ssi: [0, 0, 0, 0] + ssi_ineligible_child_allocation: [0, 0, 497, 497] + ia_ssa_care_countable_income: [2_217.5, 2_217.5, 0, 0] + ia_ssa_ihhrc_participation: [0, 0, 0, 0] + ia_ssa: [400, 0, 0, 0] + +# 441 IAC 52.1(3)"a"(6) and 6-B First-Month Client Participation p.63: "deduct +# the SSI benefit rate for one person from the client's countable income". +- name: Case 64, a resident entering from home keeps income up to the SSI individual rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + social_security_retirement: + 2026: 16_800 + ia_ssa_category: RESIDENTIAL_CARE + # Entry on January 7: the day of entry through January 31. + ia_ssa_care_partial_month_days: 25 + ia_ssa_care_initial_partial_month: true + output: + # SSI: 1,400 - 20 = 1,380 > 994, so SSI is 0. + # Participation: 1,400 - 130 - 994 = 276. + # No facility rate is entered, so the 38.47 maximum applies: + # 38.47 * 25 = 961.75; 961.75 - 276 = 685.75. + ssi: 0 + ia_ssa_care_countable_income: 1_400 + ia_ssa: 685.75 + +# 441 IAC 52.1(3)"a"(6) and 6-B p.64: "If the client had a spouse living in +# the home in the partial month before entry, deduct the SSI benefit rate for a +# married couple". +- name: Case 65, a resident entering from a home shared with a spouse keeps income up to the SSI couple rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + social_security_retirement: + 2026: 20_400 + ia_ssa_category: RESIDENTIAL_CARE + # Entry on January 7: the day of entry through January 31. + ia_ssa_care_partial_month_days: 25 + ia_ssa_care_initial_partial_month: true + person2: + age: + 2026: 60 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # The spouse is not aged, blind or disabled and has no income, so there is + # no couple computation and nothing is deemed. + # SSI: 1,700 - 20 = 1,680 > 994, so SSI is 0. + # Participation: 1,700 - 130 - 1,491 = 79; 38.47 * 25 = 961.75; + # 961.75 - 79 = 882.75. Without the entry-month flag, + # 1,700 - 130 = 1,570 covers the 961.75 and nothing is paid. + ssi_couple_computation_applies: [false, false] + ssi: [0, 0] + ia_ssa_care_countable_income: [1_700, 0] + ia_ssa: [882.75, 0] + +# 441 IAC 51.5(2) and 6-B Resources p.12: "$3,000 for a married couple living +# together"; "When the applicant is living with a spouse, count the spouse's +# resources." +- name: Case 66, an in-home care couple within the couple resource limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + ssi_countable_resources: + 2026: 2_500 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + person2: + age: + 2026: 50 + ssi_countable_resources: + 2026: 400 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # Resources: 2,500 + 400 = 2,900 <= 3,000, so person1 is eligible; the + # spouse is not aged, blind or disabled. + # SSI is 994 (20 CFR 416.1205 also counts the spouse's resources against + # 3,000). Care income 994 - 1,491 < 0, so participation is 0 and the 400 + # cost is paid. + ssi: [994, 0] + ia_ssa_eligible: [true, false] + ia_ssa_ihhrc_participation: [0, 0] + ia_ssa: [400, 0] + +- name: Case 67, an in-home care couple over the couple resource limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + ssi_countable_resources: + 2026: 2_500 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + person2: + age: + 2026: 50 + ssi_countable_resources: + 2026: 600 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # Resources: 2,500 + 600 = 3,100 > 3,000, so neither SSI nor the Iowa + # supplement is payable. + ssi: [0, 0] + ia_ssa_eligible: [false, false] + ia_ssa: [0, 0] + +- name: Case 68, RCF with an entered facility rate below the maximum. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + ia_ssa_category: RESIDENTIAL_CARE + ia_ssa_rcf_daily_rate: 35 + output: + # A lower facility rate is used as entered: 35 * 31 = 1,085; + # SSI 994, participation 994 - 130 = 864; 1,085 - 864 = 221. + ia_ssa: 221 + +# 6-B Resource and Income Guidelines for Married Couples pp.60-61 and Client +# Participation pp.68-71: spouses who received SSI are a couple in the month +# one enters a residential care facility and individuals from the month after. +- name: Case 69, manual example where a resident whose spouse stays home is budgeted alone after the entry month. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # 6-B p.69 Mr. K: Social Security of $175 a month. + social_security_retirement: 2_100 + ia_ssa_category: + 2026-03: RESIDENTIAL_CARE + 2026-04: RESIDENTIAL_CARE + # 6-B gives only the month; entry is taken as March 10, so March 10 + # through 31 are covered. + ia_ssa_care_partial_month_days: + 2026-03: 22 + ia_ssa_care_initial_partial_month: + 2026-03: true + person2: + age: 70 + # Mrs. K: Social Security of $100 a month. + social_security_retirement: 1_200 + marital_units: + couple: + 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: + # March: SSI couple 1,491 - (275 - 20) = 1,236. Care income + # (275 + 1,236) / 2 = 755.50 each; entry deduction 1,491 / 2 = 745.50; + # participation max(755.50 - 130 - 745.50, 0) = 0 (6-B p.69: "$ 0 Client + # participation for month of entry"); 38.47 * 22 = 846.34. + # April: Mr. K's SSI as an individual is 994 - (175 - 20) = 839; care + # income 175 + 839 = 1,014; participation 1,014 - 130 = 884 (6-B p.70); + # 38.47 * 30 = 1,154.10 - 884 = 270.10. + ia_ssa_rcf_couple_budget: + 2026-03: [true, false] + 2026-04: [false, false] + ia_ssa: + 2026-03: [846.34, 0] + 2026-04: [270.1, 0] + +# 441 IAC 51.4(3) and 6-B Spouses Sharing a Room p.61: "After the month of +# entry, treat the spouses as individuals when determining eligibility and +# client participation." +- name: Case 70, spouses sharing a room are budgeted as individuals after the entry month. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + # Reviewer example: Social Security of $1,500 a month. + social_security_retirement: + 2026: 18_000 + ia_ssa_category: RESIDENTIAL_CARE + person2: + age: + 2026: 70 + # Reviewer example: Social Security of $500 a month. + social_security_retirement: + 2026: 6_000 + ia_ssa_category: RESIDENTIAL_CARE + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # January is not the month of entry, so each spouse is budgeted alone. + # person1: own SSI 1,500 - 20 = 1,480 > 994, so 0; participation + # 1,500 - 130 = 1,370 covers 38.47 * 31 = 1,192.57. + # person2: own SSI 994 - (500 - 20) = 514; care income 500 + 514 = 1,014; + # participation 884; 1,192.57 - 884 = 308.57. + ia_ssa_care_countable_income: [1_500, 1_014] + ia_ssa: [0, 308.57] + +# 441 IAC 51.4(3): "Partners in a marriage who both enter the same room of the +# residential care facility in the same month will be income eligible for the +# initial month when their combined income ... is less than twice the amount of +# allowed income for one person". +- name: Case 71, spouses entering the same room in the same month are budgeted as a couple. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + # Reviewer example: Social Security of $1,500 a month. + social_security_retirement: + 2026: 18_000 + ia_ssa_category: RESIDENTIAL_CARE + # Both spouses enter on January 10: January 10 through 31. + ia_ssa_care_partial_month_days: 22 + ia_ssa_care_initial_partial_month: true + person2: + age: + 2026: 70 + # Reviewer example: Social Security of $500 a month. + social_security_retirement: + 2026: 6_000 + ia_ssa_category: RESIDENTIAL_CARE + ia_ssa_care_partial_month_days: 22 + ia_ssa_care_initial_partial_month: true + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # Neither spouse receives SSI, but both enter this month, so the couple is + # budgeted together. SSI couple: 2,000 - 20 = 1,980 > 1,491, so no SSI. + # Care income 2,000 / 2 = 1,000 each; entry deduction 1,491 / 2 = 745.50; + # participation 1,000 - 130 - 745.50 = 124.50 each; + # 38.47 * 22 = 846.34; 846.34 - 124.50 = 721.84. + ia_ssa_rcf_couple_budget: [true, true] + ia_ssa_care_countable_income: [1_000, 1_000] + ia_ssa: [721.84, 721.84] + +# 6-B p.60: "When neither spouse is receiving SSI before the entry of one or +# both into an RCF, treat the spouses separately beginning in the month of +# entry"; p.61: the resident "must now apply for and accept SSI benefits". +- name: Case 72, manual example where spouses without SSI are budgeted separately from the entry month. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # 6-B p.68 Mr. B: Social Security of $890 a month. + social_security_retirement: 10_680 + ia_ssa_category: + 2026-05: RESIDENTIAL_CARE + 2026-06: RESIDENTIAL_CARE + # 6-B gives only the month; entry is taken as May 12, so May 12 + # through 31 are covered. + ia_ssa_care_partial_month_days: + 2026-05: 20 + ia_ssa_care_initial_partial_month: + 2026-05: true + person2: + age: 70 + # Mrs. B: Social Security of $870 a month. + social_security_retirement: 10_440 + marital_units: + couple: + 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: + # May: the couple's SSI income 1,760 - 20 = 1,740 > 1,491, so no SSI and + # no couple budget. Care income 890; entry deduction 1,491 (spouse at + # home); participation max(890 - 130 - 1,491, 0) = 0; 38.47 * 20 = 769.40. + # June: SSI as an individual 994 - (890 - 20) = 124; care income 1,014; + # participation 884; 38.47 * 30 = 1,154.10 - 884 = 270.10. + ia_ssa_rcf_couple_budget: + 2026-05: [false, false] + 2026-06: [false, false] + ia_ssa: + 2026-05: [769.4, 0] + 2026-06: [270.1, 0] + +- name: Case 73, manual example of an SSI resident with an ineligible working spouse after the entry month. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # 6-B p.67 Mr. A: Social Security of $200 a month. + social_security_retirement: 2_400 + ia_ssa_category: + 2026-06: RESIDENTIAL_CARE + 2026-07: RESIDENTIAL_CARE + # 6-B gives only the month; entry is taken as June 15, so June 15 + # through 30 are covered. + ia_ssa_care_partial_month_days: + 2026-06: 16 + ia_ssa_care_initial_partial_month: + 2026-06: true + # 6-B p.68: "Diversion for Mrs. A (994 - 457.50 ...)". + ia_ssa_care_additional_deductions: + 2026-07: 536.5 + person2: + age: 60 + # Mrs. A: earnings of $1,000 a month. + employment_income: 12_000 + marital_units: + couple: + 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: + # June: SSI with spousal deeming 1,491 - 647.50 = 843.50 (6-B p.67). Mrs. A + # is not aged, blind or disabled, so there is no couple budget. Care income + # 200 + 843.50 = 1,043.50; entry deduction 1,491 (spouse at home); + # participation max(1,043.50 - 130 - 1,491, 0) = 0, as on p.67; + # 38.47 * 16 = 615.52. First-month deemed spouse income is not modeled. + # July: SSI as an individual 994 - (200 - 20) = 814 (6-B p.68); care + # income 1,014; participation 1,014 - 130 - 536.50 = 347.50 (6-B p.68); + # 38.47 * 31 = 1,192.57 - 347.50 = 845.07. + ssi: + 2026-06: [843.5, 0] + ia_ssa: + 2026-06: [615.52, 0] + 2026-07: [845.07, 0] + +# 6-B Resources p.12: "When the applicant is not living with the spouse, do not +# count the spouse's resources." +- name: Case 74, a resident's resources are tested alone after the entry month. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + # $2,500 of resources, the reviewer's figure in Cases 66-67. + ssi_countable_resources: + 2026: 2_500 + ia_ssa_category: RESIDENTIAL_CARE + person2: + age: + 2026: 70 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # January is not the month of entry, so person1's own 2,500 is tested + # against the 2,000 individual limit and fails. person2, at home, owns + # nothing and passes either way: tested alone under p.12, or pooled, as + # the model still pools a spouse in an ordinary arrangement (2,500 within + # the 3,000 couple limit) because federal SSI keeps the couple. + ia_ssa_eligible: [false, true] + ia_ssa: [0, 0] + +# 441 IAC 52.1(3)"a"(1) deducts "impairment-related work expenses, as defined +# by SSI plus $65 plus one-half of any remaining earned income"; 6-B p.65 Mr. L +# has earnings of $333 and expenses of $100. +- name: Case 75, a resident without SSI enters impairment-related work expenses at one-half. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + # Mr. L's $700 of Social Security would qualify him for SSI, so $1,100 a + # month is used for a resident who receives none. + social_security_retirement: + 2026: 13_200 + # Mr. L: earned income of $333 a month. + employment_income: + 2026: 3_996 + ia_ssa_category: RESIDENTIAL_CARE + # One-half of Mr. L's $100 of impairment-related work expenses. + ia_ssa_care_additional_deductions: 50 + output: + # SSI: (1,100 - 20) + (333 - 65) / 2 = 1,214 > 994, so SSI is 0. + # Rule: 1,100 + (333 - 100 - 65) / 2 = 1,184; 1,184 - 130 = 1,054. + # Model: care income 1,100 + 134 = 1,234; 1,234 - 130 - 50 = 1,054. + # 1,192.57 - 1,054 = 138.57. + ssi: 0 + ia_ssa_care_countable_income: 1_234 + ia_ssa: 138.57 + +# 20 CFR 416.1124(c)(22) excludes "Interest and dividend income from a +# countable resource"; Manual 8-E Dividends p.23 and Interest Income p.36. +- name: Case 76, a resident's interest is excluded from care income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + # Reviewer example: $5 a month of interest on savings. + interest_income: + 2026: 60 + ia_ssa_category: RESIDENTIAL_CARE + output: + # SSI: the $20 general exclusion covers the $5, so SSI is 994. Care income + # 0 + 994 = 994; participation 864; 1,192.57 - 864 = 328.57. + ssi: 994 + ia_ssa_care_countable_income: 994 + ia_ssa: 328.57 + +# 6-B Making the Family-Life Home Payment p.35: "For a recipient who has only +# SSI and no other income (and hence no $20 to disregard), an additional $20 +# payment is necessary". +- name: Case 77, a family-life home resident whose only other income is interest gets the 20 dollar payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + # Reviewer example: $5 a month of interest on savings. + interest_income: + 2026: 60 + ia_ssa_category: FAMILY_LIFE_HOME + output: + # Interest is excluded under 416.1124(c)(22), so only SSI is received: + # SSA pays 142 and the state pays 20. + ssi: 994 + ia_ssa_federal: 142 + ia_ssa: 162 + +- name: Case 78, a family-life home resident with 10 dollars of Social Security gets no 20 dollar payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + # Reviewer example: $10 a month of other income. + social_security_retirement: + 2026: 120 + ia_ssa_category: FAMILY_LIFE_HOME + output: + # SSI 994 (the $20 exclusion covers the $10). Care income 10 + 994 = 1,004 + # is below 1,156, so SSA pays 142; other income rules out the state's $20. + ssi: 994 + ia_ssa_care_countable_income: 1_004 + ia_ssa_federal: 142 + ia_ssa: 142 + +- name: Case 79, without marital units an in-home care parent is not paired with an adult child. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + # Reviewer example: Social Security of $800 a month and a $400 cost. + social_security_retirement: + 2026: 9_600 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + person2: + # A variant of the reviewer's adult child: a 22-year-old full-time + # student earning $1,000 a month. + age: + 2026: 22 + is_full_time_student: + 2026: true + employment_income: + 2026: 12_000 + is_tax_unit_dependent: + 2026: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # The child is the parent's tax dependent, so SSI's spouse test does not + # pair them and the parent gets the individual allowance. The child is + # not under 18, so there is no dependent-child allowance. + # SSI 994 - (800 - 20) = 214; care income 800 + 214 = 1,014; + # participation 1,014 - 994 = 20; 400 - 20 = 380. + ia_ssa_has_spouse: [false, false] + ssi: [214, 0] + ia_ssa_ihhrc_participation: [20, 0] + ia_ssa: [380, 0] + +# 6-B Deeming Parents' Resources p.47 Child B: "$ 5,500 Parent's resources - +# 3,000 Exempt $ 2,500 Deemed to Child B". +- name: Case 80, without marital units parental resources are still deemed to an in-home care child. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + bank_account_assets: + 2026: 5_500 + person2: + age: + 2026: 40 + person_id: + 2026: 2 + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2026: IA + output: + # The three people share one default marital unit, which is not a couple. + # The parent links give two parents, so the allowance is 3,000: + # 5,500 - 3,000 = 2,500 deemed to the child exceeds 2,000. + ia_ssa_resources_deemed_from_parents: [0, 0, 2_500] + ia_ssa: [0, 0, 0] + +# SI 02001.005 and SI 02001.010: SSA drops digits beyond the third decimal, +# rounds up to the cent and pays at least $1. +- name: Case 81, a blind supplement of 50 cents is paid at the 1 dollar minimum. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + is_blind: + 2026: true + # Reviewer example: Social Security of $1,035.50 a month. + social_security_retirement: + 2026: 12_426 + output: + # 1,035.50 - 20 = 1,015.50 > 994, so SSI is 0; 994 + 22 - 1,015.50 = 0.50. + ssi: 0 + ia_ssa_federal: 1 + ia_ssa: 1 + +- name: Case 82, a blind supplement is rounded up to the cent. + period: 2026-01 + absolute_error_margin: 0.001 + input: + state_code: + 2026: IA + age: + 2026: 65 + is_blind: + 2026: true + # Reviewer boundary income: 1,030.445 a month. + social_security_retirement: + 2026: 12_365.34 + output: + # 1,030.445 - 20 = 1,010.445; 1,016 - 1,010.445 = 5.555, rounded up to 5.56. + ia_ssa_federal: 5.56 + ia_ssa: 5.56 + +# 6-B Verification p.9: "For an SSI recipient, accept the Social Security +# Administration's determination of SSI eligibility as verification that +# income, resources, and age, blindness or disability requirements have been +# met." 20 CFR 416.1202(b)(2) waives parental resource deeming for some +# children in Medicaid home care. +- name: Case 83, a blind SSI child exempt from parental resource deeming keeps the blind supplement. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + # Reviewer example: two parents with $6,000. + bank_account_assets: + 2026: 6_000 + person2: + age: + 2026: 40 + person_id: + 2026: 2 + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + is_blind: + 2026: true + ssi_resource_deeming_waiver: true + marital_units: + parents: + members: [person1, person2] + child: + 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: + 2026: IA + output: + # SSA deems nothing under the waiver and pays 994; Iowa accepts it, so the + # child's resources are 0 and the 22 blind supplement is paid. + is_ssi_resource_deeming_child: [false, false, false] + ssi: [0, 0, 994] + ia_ssa_resources_deemed_from_parents: [0, 0, 0] + ia_ssa: [0, 0, 22] + +# 441 IAC 51.4(3): income eligible when income "is less than 31 times the +# maximum per diem rate". +- name: Case 84, residential care participation equal to the month's cost pays nothing. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + # Boundary income: 1,322.57 a month, where participation equals the cost. + social_security_retirement: + 2026: 15_870.84 + ia_ssa_category: RESIDENTIAL_CARE + output: + # Participation 1,322.57 - 130 = 1,192.57 = 38.47 * 31, so nothing is paid. + ssi: 0 + ia_ssa: 0 + +# 6-B Income (DP) p.25: group income "must be less than the applicable +# assistance standard", 994 + 518 = 1,512 for one person. +- name: Case 85, dependent-person group income one cent below the standard pays the 1 dollar minimum. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + # Reviewer boundary income: 1,531.99 a month. + social_security_retirement: + 2026: 18_383.88 + ia_ssa_category: DEPENDENT_PERSON + output: + # 1,531.99 - 20 = 1,511.99 < 1,512; 518 - (1,511.99 - 994) = 0.01, paid at $1. + ssi: 0 + ia_ssa_federal: 1 + ia_ssa: 1 + +- name: Case 86, dependent-person group income at the standard is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + # Reviewer boundary income: 1,532 a month. + social_security_retirement: + 2026: 18_384 + ia_ssa_category: DEPENDENT_PERSON + output: + # 1,532 - 20 = 1,512 is not less than 1,512. + ia_ssa_federal: 0 + ia_ssa: 0 + +# Iowa Code 249.3(4)(a) names a person 65 or older or disabled; 441 IAC 51.7(2) +# requires "all eligibility requirements for supplemental security income +# benefits other than limits on substantial gainful activity and income", which +# include blindness (6-B pp.10, 76). The model follows 51.7(2). +- name: Case 87, a blind SMME applicant under 65 qualifies under 441 IAC 51.7(2). + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 50 + is_blind: + 2026: true + # SSDI of $2,020 a month, above the blind SSI limit and 120 percent of + # poverty. + social_security_disability: + 2026: 24_240 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + output: + # SSI countable income 2,020 - 20 = 2,000 exceeds both 994 and the blind + # limit of 1,016, so SSI and the blind supplement are 0. SMME income 2,000 + # exceeds 1.2 * 15,960 / 12 = 1,596. + ssi: 0 + ia_ssa_federal: 0 + ia_ssa_smme_countable_income: 2_000 + ia_ssa: 1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml index 3c7b6bc8d5d..35f557db0ed 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/integration.yaml @@ -16,6 +16,9 @@ members: [person1, person2] state_code: IA output: + # SSI couple rate 1,491, split 745.50 each; only the blind spouse gets 22. + ssi: [745.5, 745.5] + ia_ssa_federal: [22, 0] ia_ssa: [22, 0] - name: Case 2, two blind spouses. @@ -37,6 +40,9 @@ members: [person1, person2] state_code: IA output: + # SSI couple rate 1,491, split 745.50 each; each blind spouse gets 22. + ssi: [745.5, 745.5] + ia_ssa_federal: [22, 22] ia_ssa: [22, 22] - name: Case 3, dependent-person grant is once per eligible couple. @@ -58,6 +64,9 @@ members: [person1, person2] state_code: IA output: + # Group income 1,491 < 2,009, so the couple's 518 is split 259 each. + ssi: [745.5, 745.5] + ia_ssa_federal: [259, 259] ia_ssa: [259, 259] - name: Case 4, mixed blind dependent-person couple follows state manual. @@ -80,6 +89,9 @@ members: [person1, person2] state_code: IA output: + # Couple level 518 + 22 = 540 (6-B p.26 $2,031 - $1,491), split 270 each. + ssi: [745.5, 745.5] + ia_ssa_federal: [270, 270] ia_ssa: [270, 270] - name: Case 5, family-life home eligible couple. @@ -101,6 +113,10 @@ members: [person1, person2] state_code: IA output: + # Couple amount 2 * 1,156 - 1,491 - 20 = 801, split 400.50 each; the + # SSI-only couple shares one 20 top-up. + ssi: [745.5, 745.5] + ia_ssa_federal: [400.5, 400.5] ia_ssa: [410.5, 410.5] - name: Case 6, in-home care counts ineligible spouse income. @@ -123,6 +139,9 @@ members: [person1, person2] state_code: IA output: + # SSI deems the spouse's 1,700: 1,700 - 20 = 1,680 > 1,491, so SSI is 0. + # Care income 1,700; participation 1,700 - 1,491 = 209; 400 - 209 = 191. + ssi: [0, 0] ia_ssa: [191, 0] - name: Case 7, in-home couple gets only one earnings disregard. @@ -148,6 +167,12 @@ members: [person1, person2] state_code: IA output: + # SSI: (3,000 - 20 - 65) / 2 = 1,457.50 < 1,491, so 33.50, or 16.75 each. + # Care income (3,000 - 65) / 2 + 33.50 = 1,501; participation + # 1,501 - 1,491 = 10; (800 - 10) / 2 = 395. + ssi: [16.75, 16.75] + ia_ssa_care_countable_income: [1_501, 1_501] + ia_ssa_ihhrc_participation: [10, 10] ia_ssa: [395, 395] - name: Case 8, annual blind allowance in SNAP income and benefit totals. @@ -211,3 +236,66 @@ ia_ssa_care_countable_income: [772, 772] ia_ssa_federal: [409, 409] ia_ssa: [419, 419] + +- name: Case 11, certifying one spouse gives the couple the dependent-person level. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + ia_ssa_category: DEPENDENT_PERSON + person2: + # No category entered, so person2 defaults to REGULAR. + age: 65 + marital_units: + couple: + members: [person1, person2] + households: + hh: + members: [person1, person2] + state_code: IA + output: + # 441 IAC 52.1(2)"b" sets one standard for the "Aged or disabled client, + # eligible spouse, and a dependent relative", so certifying either spouse + # applies the couple level. + # SSI couple rate 1,491, split 745.50 each. Group income 1,491 + 0 is + # below the 1,491 + 518 = 2,009 standard, so the couple's 518 supplement + # is split 259 each (as in Case 3, where both spouses are certified). + ssi: [745.5, 745.5] + ia_ssa_federal: [259, 259] + ia_ssa: [259, 259] + +- name: Case 12, a dependent-person spouse and an in-home care spouse share the couple level. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + ia_ssa_category: DEPENDENT_PERSON + person2: + age: 65 + ia_ssa_category: IN_HOME_CARE + # Within the $480.55 monthly ceiling for one person (6-B p.41). + ia_ssa_ihhrc_monthly_cost: 400 + marital_units: + couple: + members: [person1, person2] + households: + hh: + members: [person1, person2] + state_code: IA + output: + # SSI couple rate 1,491, split 745.50 each. Certifying person1 applies the + # couple dependent-person level whatever person2's category (441 IAC + # 52.1(2)"b"): group income 1,491 is below 2,009, so the 518 supplement + # is split 259 each. + ssi: [745.5, 745.5] + ia_ssa_federal: [259, 259] + # In-home care: couple income 1,491 less the 1,491 couple maintenance + # allowance leaves participation 0, so the 400 cost is paid in full. + ia_ssa_ihhrc_participation: [0, 0] + ia_ssa_ihhrc_amount: [0, 400] + # 259 + 0 and 259 + 400. + ia_ssa: [259, 659] 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 469062191d7..edd5dda7bbd 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 @@ -8,8 +8,10 @@ class ia_ssa(Variable): definition_period = MONTH unit = USD reference = ( - # Iowa Code 249.3 - "https://www.legis.iowa.gov/docs/code/249.pdf#page=1", + # Iowa Code 249.3; PDF pages 2-3 + "https://www.legis.iowa.gov/docs/code/249.pdf#page=2", + # 441 IAC 51.4(3) and 51.7(6); PDF pages 1-2 + "https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=1", # 441 IAC 52.1; PDF pages 1-2 "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", # PDF pages 35, 41-49, 59-74, 76-78 @@ -27,10 +29,46 @@ def formula(person, period, parameters): extra = max_(person("ia_ssa_care_additional_deductions", period), 0) partial = person("ia_ssa_care_partial_month_days", period) days = where(partial > 0, min_(partial, period.days), period.days) - # RCF income eligibility uses a 31-day ceiling; payment uses the - # actual covered days billed by the provider. - rate = min_(max_(person("ia_ssa_rcf_daily_rate", period), 0), p.rcf_daily_limit) - rcf_participation = max_(income - p.rcf_personal_needs - extra, 0) + joint = person("ssi_couple_computation_applies", period) + # NOTE: 441 IAC 52.1(3): "For periods of eligibility beginning July 1, + # 2017, and thereafter, payment to a recipient in a licensed residential + # care facility will be based on the maximum per diem rate", and 51.4(3) + # tests income against "31 times the maximum per diem rate". 6-B + # Billing and Payments p.72 still describes "two options": a + # cost-related per diem rate "established by the Department + # specifically for each facility" of up to $38.47, or "A flat per diem + # rate ... $17.86 beginning February 1, 2004". The model follows the + # rule and pays the maximum rate unless a lower facility rate is + # entered (ia_ssa.yaml Cases 19, 20 and 68). + entered_rate = max_(person("ia_ssa_rcf_daily_rate", period), 0) + rate = where( + entered_rate > 0, + min_(entered_rate, p.rcf_daily_limit), + p.rcf_daily_limit, + ) + # 441 IAC 52.1(3)"a"(6): "The income of a resident who lived at home in + # the month of entry will not be applied to the cost of care except to + # the extent the income exceeds the SSI benefit for one person or for a + # married couple if the resident also had a spouse living in the home + # in the month of entry." In a couple-budget entry month + # (ia_ssa_rcf_couple_budget) each spouse's care income is half the + # couple's, so each deducts half the couple rate. + # NOTE: 6-B First-Month Client Participation pp.63-64 deducts "the SSI + # benefit rate for one person" or "for a married couple", as the rule + # does, but later lets clients from an independent living arrangement + # "keep enough of the first month's income to meet maintenance or + # living expenses from the previous living arrangement, but do not + # disregard an amount that is over the SSI standard". The model follows + # the rule's fixed amount (ia_ssa.yaml Cases 64-65). + has_spouse = person("ia_ssa_has_spouse", period) + entry = where(has_spouse, federal.amount.couple, federal.amount.individual) + entry = where( + person("ia_ssa_rcf_couple_budget", period), entry / 2, entry + ) * person("ia_ssa_care_initial_partial_month", period) + rcf_participation = max_(income - p.rcf_personal_needs - extra - entry, 0) + # Paying the covered days less participation, floored at zero, matches + # the 51.4(3) income test in a 31-day month and pays nothing in a + # shorter month that income covers (52.1(3)"d"). rcf = max_(rate * days - rcf_participation, 0) ihhrc = person("ia_ssa_ihhrc_amount", period) # 6-B Making the Family-Life Home Payment: "For a recipient who has @@ -39,11 +77,15 @@ def formula(person, period, parameters): # exclusion, so the federal parameter is used. Only positive amounts # count as other income, and the eligible couple shares one $20. receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) - joint = person("ssi_couple_computation_applies", period) sources = federal.income.sources + # Interest and dividends are excluded from income as in + # ia_ssa_care_countable_income (20 CFR 416.1124(c)(22)), so they are + # not other income here (ia_ssa.yaml Case 77). + excluded = p.excluded_unearned_sources has_other_income = np.zeros(person.count, dtype=bool) for source in list(sources.earned) + list(sources.unearned): - has_other_income = has_other_income | (person(source, period) > 0) + if source not in excluded: + has_other_income = has_other_income | (person(source, period) > 0) has_other_income = where( joint, person.marital_unit.any(has_other_income), has_other_income ) @@ -55,9 +97,11 @@ def formula(person, period, parameters): * federal.income.exclusions.general / where(joint, max_(recipients, 1), 1) ) - # The SMME standard uses the federal poverty guideline for the - # recipient's marital unit (6-B Income (SMME)). - size = person.marital_unit.nb_persons() + # 441 IAC 51.7(6) and 6-B Income (SMME) p.77 set no family size for + # the poverty guideline. The model uses the recipient and any spouse, + # matching ia_ssa_smme_countable_income, which combines an eligible + # couple's income. + size = where(has_spouse, 2, 1) fpg = parameters(period).gov.hhs.fpg poverty = ( fpg.first_person.CONTIGUOUS_US diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_additional_deductions.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_additional_deductions.py index 92984389ce0..d04a9f9e5f6 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_additional_deductions.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_additional_deductions.py @@ -8,11 +8,11 @@ class ia_ssa_care_additional_deductions(Variable): definition_period = MONTH unit = USD defined_for = StateCode.IA - documentation = "Verified monthly deductions from care income beyond those the model applies: dependent and spouse allocations and unmet medical needs, and for residential care also approved first-month expenses of the previous living arrangement and work-related deductions. Excludes the home maintenance or personal needs allowance and the $65 and one-half earnings exclusions. Key each amount to its month; a yearly entry is spread evenly over the months." + documentation = "Verified monthly deductions from care income beyond those the model applies: unmet medical needs; for in-home health-related care, the allowance for a dependent other than an SSI-ineligible child in the tax unit; for residential care, the spouse and dependent diversions (omit the spouse diversion in a month of entry, when the SSI couple rate is deducted instead), income used that month to pay for care in another facility or setting and, for a resident who receives no SSI, one-half of impairment-related work expenses, because this input is subtracted after the one-half earnings exclusion. Enter no impairment-related work expenses for an SSI recipient: SSA's payment already offsets them. Enter a deduction a couple shares on one spouse only; in-home care adds the couple's entries together. Excludes the home maintenance, dependent-child and personal needs allowances, the entry-month SSI rate deduction and the $65 and one-half earnings exclusions. Key each amount to its month; a yearly entry is spread evenly over the months." reference = ( # 441 IAC 52.1(3)"a" "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", - # PDF pages 42-43, 61-64 + # PDF pages 42-44, 59, 61-65, 68 "https://hhs.iowa.gov/media/3987/download?inline=#page=42", ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py index 7db74fb7456..86596449aa9 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py @@ -11,35 +11,62 @@ class ia_ssa_care_countable_income(Variable): definition_period = MONTH unit = USD defined_for = StateCode.IA - documentation = "Whole marital-group income for adult in-home care; individual income for other care. A child in in-home care receives income deemed from parents under the Iowa method. First-month spouse deeming and deductions absent from the federal SSI income inputs are not modeled." + documentation = "Care income without the $20 general exclusion: SSI countable income plus SSI. In-home care counts an adult's spouse's income. An eligible family-life home couple, and a residential care couple in the month of entry, split the couple's income. After the month of entry, a married resident counts own income plus the SSI individual amount from it. A child in in-home care receives income deemed from parents under the Iowa method. Interest and dividends are excluded. First-month deeming from an ineligible spouse, and deductions absent from the federal SSI income inputs, are not modeled." reference = ( # 441 IAC 52.1(3)"a" "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", - # PDF pages 34, 41-42, 49, 59-63 + # PDF pages 34, 40-42, 46, 49, 58-65, 67-71 "https://hhs.iowa.gov/media/3987/download?inline=#page=34", ) def formula(person, period, parameters): + p = parameters(period).gov.states.ia.hhs.ssa + ssi = parameters(period).gov.ssa.ssi category = person("ia_ssa_category", period) - home = category == category.possible_values.IN_HOME_CARE + c = category.possible_values + home = category == c.IN_HOME_CARE + rcf = category == c.RESIDENTIAL_CARE joint = person("ssi_couple_computation_applies", period) + spouse = person("ia_ssa_has_spouse", period) adult = ~person("is_child", period.this_year) - combine = where(home, adult & (person.marital_unit.nb_persons() == 2), joint) + combine = select( + [home, rcf], + [adult & spouse, person("ia_ssa_rcf_couple_budget", period)], + default=joint, + ) + # NOTE: 441 IAC 52.1(3)"a"(1) deducts "impairment-related work + # expenses, as defined by SSI plus $65 plus one-half of any remaining + # earned income" (6-B p.65, Mr. L). Neither federal SSI nor this + # variable models those expenses (issue 3669). For a resident without + # SSI, entering one-half of them in ia_ssa_care_additional_deductions + # reproduces the rule (ia_ssa.yaml Case 75). For an SSI recipient, + # SSA's payment rises by the same one-half, so care income does not + # change (6-B p.59). earned = max_( person("ssi_earned_income", period) - person("ssi_blind_or_disabled_working_student_exclusion", period), 0, ) - # 6-B excludes one-third of child support a child receives from an - # absent parent. Federal SSI does not apply 20 CFR 416.1124(c)(11) yet - # (issue 10242), so the shared federal share is read here directly. + # NOTE: 20 CFR 416.1124(c)(22) excludes "Interest and dividend income + # from a countable resource", as Manual 8-E Dividends and Interest + # Income do. Federal SSI still counts them (issue 10079), so the + # sources in excluded_unearned_sources are dropped here and from the + # family-life home $20 test in ia_ssa (ia_ssa.yaml Cases 76-77). + # Remove the list once issue 10079 is fixed, or they are excluded + # twice. SMME income (ia_ssa_smme_countable_income) and the SSA-paid + # amounts (ia_ssa_federal) use SSI countable income, so they count + # interest and dividends until then. The 8-E exceptions for excluded + # resources are not modeled. + # NOTE: 6-B excludes one-third of child support a child receives from + # an absent parent. Federal SSI does not apply 20 CFR 416.1124(c)(11) + # yet (issue 10242), so the shared federal share is read here; remove + # it once issue 10242 is fixed. unearned = max_( person("ssi_unearned_income", period) - - person("interest_income", period) - - person("dividend_income", period) + - add(person, period, p.excluded_unearned_sources) - ~adult * person("child_support_received", period) - * parameters(period).gov.ssa.ssi.income.exclusions.child_support_share, + * ssi.income.exclusions.child_support_share, 0, ) # 6-B: "do not rely on SSI deeming calculations for children" in @@ -50,7 +77,29 @@ def formula(person, period, parameters): person("ssi_unearned_income_deemed_from_ineligible_parent", period), ) unearned = unearned + ~adult * deemed - benefit = person("ssi", period) + # NOTE: 6-B pp.60-61 treats spouses "as individuals beginning the month + # after the month of entry", and the examples on pp.68-71 then use the + # resident's own SSI (Mr. K: "$ 839 SSI benefit"). A resident whose + # income is below the SSI rate "must now apply for and accept SSI + # benefits" (p.61). The model therefore assumes SSA pays each spouse as + # an individual from that month, and credits that amount even to a + # resident who does not take up SSI. Federal SSI has no input for + # spouses who live apart and keeps the couple or deemed amount, so the + # SSI individual amount is computed here from the resident's own income + # (ia_ssa.yaml Cases 69-73). + individual_ssi = max_( + ssi.amount.individual + - _apply_ssi_exclusions( + earned * MONTHS_IN_YEAR, + unearned * MONTHS_IN_YEAR, + parameters, + period, + ) + / MONTHS_IN_YEAR, + 0, + ) + separated = rcf & spouse & ~person("ia_ssa_care_initial_partial_month", period) + benefit = where(separated, individual_ssi, person("ssi", period)) earned = where(combine, person.marital_unit.sum(earned), earned) unearned = where(combine, person.marital_unit.sum(unearned), unearned) benefit = where(combine, person.marital_unit.sum(benefit), benefit) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_initial_partial_month.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_initial_partial_month.py new file mode 100644 index 00000000000..9ebe3315ce4 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_initial_partial_month.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ia_ssa_care_initial_partial_month(Variable): + value_type = bool + entity = Person + label = "Iowa SSA first partial month of in-home or residential care" + definition_period = MONTH + defined_for = StateCode.IA + default_value = False + documentation = "Set for a first month of in-home health-related care service that is less than a full month, or for the month a resident enters a residential care facility after living at home earlier that month. In-home care then requires no client participation. Residential care deducts the SSI benefit rate for one person, or for a couple when a spouse lived in the home. For a married resident, the month also sets the couple budget (ia_ssa_rcf_couple_budget) when either spouse received SSI or both spouses enter that month; later months budget each spouse alone. Key the entry to its month and enter the covered days in ia_ssa_care_partial_month_days." + reference = ( + # 441 IAC 52.1(3)"a"(6) + "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=2", + # 441 IAC 177.8(2)"b" (IAC 8/5/26) + "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=4", + # 441 IAC 177.10(2)"b" (IAC 2/5/25) + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=5", + # PDF pages 42, 60-61, 63-64 + "https://hhs.iowa.gov/media/3987/download?inline=#page=42", + ) + + def formula(person, period, parameters): + # A formula stops a one-month input from carrying into later months. + return False 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 ab156f123e1..c85f31d07de 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 @@ -18,14 +18,18 @@ class ia_ssa_category(Variable): definition_period = MONTH possible_values = IASSACategory default_value = IASSACategory.REGULAR - # PDF pages 5-6, 20, 24, 30, 41, 59, 76 + # PDF pages 5-6, 20, 24, 30, 40-41, 57-61, 76 reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=5" documentation = """ Special categories require agency certification of the dependency or care arrangement, benefit pursuit, and procedural eligibility. DEPENDENT_PERSON requires a selected co-resident relative who is ineligible for SSI/FIP, satisfies the marital restrictions and does not deem income to the client. - Select it for both members of an eligible SSI couple sharing one dependent. - For residential care reflect separate SSI claims after the entry month. + For an eligible SSI couple sharing one dependent, certifying either member + applies the couple level. Certification also covers the dependent's own + resources, which 441 IAC 51.5(2) counts with the recipient's; the model + tests only the recipient's and spouse's resources. + For residential care, set ia_ssa_care_initial_partial_month in the month + of entry; a married resident is budgeted alone from the next month. NONE also excludes the blind allowance; otherwise it may accompany care. """ diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_dependent_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_dependent_countable_income.py index 5b496919f75..c77e31a32c9 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_dependent_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_dependent_countable_income.py @@ -7,6 +7,7 @@ class ia_ssa_dependent_countable_income(Variable): label = "Countable income of Iowa SSA selected dependent" definition_period = MONTH unit = USD + default_value = 0 # PDF pages 24-28 reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=24" documentation = "Verified dependent income after 6-B deductions, including the special parent-of-child calculation and only one $20 exclusion per dependent group. The dependent does not receive the recipient's half-earnings exclusion. An entry carries into later months until it is changed." 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 d001219fec8..d4b6d53776b 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 @@ -9,17 +9,17 @@ class ia_ssa_eligible(Variable): defined_for = StateCode.IA reference = ( # Iowa Code 249.3 - "https://www.legis.iowa.gov/docs/code/249.pdf#page=1", + "https://www.legis.iowa.gov/docs/code/249.pdf#page=2", # PDF pages 6-12 "https://hhs.iowa.gov/media/3987/download?inline=#page=6", "https://www.ecfr.gov/current/title-20/section-416.1202", + "https://www.ecfr.gov/current/title-20/section-416.1205", ) def formula(person, period, parameters): category = person("ia_ssa_category", period) c = category.possible_values resource = person("ssi_countable_resources", period.this_year) - joint = person("ssi_claim_is_joint", period.this_year) community = ( (category == c.IN_HOME_CARE) | (category == c.SMME) @@ -27,15 +27,27 @@ def formula(person, period, parameters): | (category == c.DEPENDENT_PERSON) | (category == c.FAMILY_LIFE_HOME) ) - # 6-B Resources: "When the applicant is living with a spouse, count the - # spouse's resources." - couple = (person.marital_unit.nb_persons() == 2) & (community | joint) + # 6-B Resources p.12: "When the applicant is living with a spouse, + # count the spouse's resources. When the applicant is not living with + # the spouse, do not count the spouse's resources." A residential care + # resident lives apart from the spouse after the month of entry (6-B + # p.60), so only the couple-budget entry month pools resources + # (ia_ssa.yaml Case 74). + # NOTE: The spouse who stays at home still pools resources with the + # resident after the month of entry, though p.12 would test that + # spouse alone. Federal SSI in the model has no input for spouses who + # live apart and keeps them a couple, and that spouse's SSA income + # comes from federal SSI, so this belongs with the federal treatment of + # spouses living apart. + couple = person("ia_ssa_has_spouse", period) & ( + community | person("ia_ssa_rcf_couple_budget", period) + ) resource = where(couple, person.marital_unit.sum(resource), resource) resource = resource + person("ia_ssa_resources_deemed_from_parents", period) # 6-B Resources prints "$2,000 for an individual" and "$3,000 for a # married couple living together" under 20 CFR 416.1202; these equal - # the SSI limits, so the federal parameters are used and an SSI reform - # carries over to Iowa. + # the SSI limits of 20 CFR 416.1205, so the federal parameters are used + # and an SSI reform carries over to Iowa. limit = parameters(period).gov.ssa.ssi.eligibility.resources.limit return person("ia_ssa_nonfinancial_eligible", period) & ( resource <= where(couple, limit.couple, limit.individual) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py index dd096f40aeb..af595815156 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py @@ -11,8 +11,10 @@ class ia_ssa_federal(Variable): definition_period = MONTH unit = USD reference = ( - # 441 IAC 52.1(1), (2) and (4) + # 441 IAC 52.1(1), (2) and (4); PDF pages 1-2 "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", + # 441 IAC 51.5(1) + "https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=2", # PDF pages 20, 24-28, 30, 34-35 "https://hhs.iowa.gov/media/3987/download?inline=#page=20", "https://secure.ssa.gov/poms.nsf/lnx/0501415058#f", @@ -53,11 +55,13 @@ def formula(person, period, parameters): # less than $518 per month") and 441 IAC 51.5(1) ("must be less than # the amount established by the department") exclude it. The model # follows 51.5(1) and p.25 (ia_ssa.yaml Case 6). - dp = ( - (category == c.DEPENDENT_PERSON) - & (dependent < p.dependent_amount) - & (group_income < need) - ) + # The dependent-person standards are couple standards (441 IAC + # 52.1(2)"b", "d" and "e"), so certifying either spouse of an eligible + # couple applies the couple level (integration.yaml Cases 11-12), + # whatever the other spouse's category. + certified = category == c.DEPENDENT_PERSON + certified = where(joint, person.marital_unit.any(certified), certified) + dp = certified & (dependent < p.dependent_amount) & (group_income < need) # 6-B: the family-life home standard is "$1,156", and the maximum # supplement is "$162 ($1,156 - $994 SSI standard)". SSA pays at most # $142 because it applies the $20 general exclusion. The couple amount @@ -73,6 +77,19 @@ def formula(person, period, parameters): family_life_couple = 2 * family_life_need - ssi.amount.couple - general federal_la = person("ssi_federal_living_arrangement", period) medical = federal_la == federal_la.possible_values.MEDICAL_TREATMENT_FACILITY + # NOTE: 441 IAC 52.1(4) sets $22 as "The standard for a blind recipient + # not receiving another type of state supplementary assistance". 6-B + # Blind Supplement p.20 excludes the blind supplement "when determining + # eligibility for other SSA programs the person may be receiving + # simultaneously. For example, the blind supplement is not countable + # income to determine client participation or eligibility for the RCF + # supplement", and p.42 says "Do not count the $22 special blind + # allowance when determining client participation" for in-home care. + # POMS SI 01415.058 F.1 code A pays a blind recipient "who does not live + # in any other State living arrangement variation", the SSA-coded + # dependent-person and family-life home rows, whose levels include the + # $22. The model follows the manual and POMS and pays the $22 with + # residential care and in-home care (ia_ssa.yaml Cases 16 and 27). individual_rate = ( dp * p.dependent_amount + flh * family_life_individual diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_has_spouse.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_has_spouse.py new file mode 100644 index 00000000000..d1da130610a --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_has_spouse.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.ssa.ssi.eligibility.resources.deemed._ssi_spouses import ( + _ssi_spouse_index, +) + + +class ia_ssa_has_spouse(Variable): + value_type = bool + entity = Person + label = "Iowa SSA spouse in the marital unit" + definition_period = MONTH + defined_for = StateCode.IA + reference = ( + "https://hhs.iowa.gov/media/3987/download?inline=#page=12", + "https://www.ecfr.gov/current/title-20/section-416.1806", + ) + + def formula(person, period, parameters): + # 6-B Resources p.12: "When the applicant is living with a spouse, + # count the spouse's resources." A two-person marital unit is a couple + # only when SSI's spouse test pairs its members, so the default unit of + # a situation without marital units does not pair a parent with an + # adult child the parent claims (ia_ssa.yaml Case 79). A default unit + # of three or more people budgets each member alone. + couple_unit = person.marital_unit.nb_persons() == 2 + return couple_unit & (_ssi_spouse_index(person, period) >= 0) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py index 13f2b48274f..0c695d18a33 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_amount.py @@ -9,8 +9,10 @@ class ia_ssa_ihhrc_amount(Variable): unit = USD defined_for = StateCode.IA reference = ( - # 441 IAC 177.8(2) + # 441 IAC 177.8(2) (IAC 8/5/26) "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=4", + # 441 IAC 177.10(2) (IAC 2/5/25); PDF pages 4-5 + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=4", # PDF pages 41-42 "https://hhs.iowa.gov/media/3987/download?inline=#page=41", ) @@ -25,7 +27,12 @@ def formula(person, period, parameters): partial = person("ia_ssa_care_partial_month_days", period) days = where(partial > 0, min_(partial, period.days), period.days) covered_cost = cost * days / period.days * approved - total_cost = person.marital_unit.sum(covered_cost) + # A couple's approved costs share one participation; others are alone. + total_cost = where( + person("ia_ssa_has_spouse", period), + person.marital_unit.sum(covered_cost), + covered_cost, + ) payable = max_(total_cost - person("ia_ssa_ihhrc_participation", period), 0) # Allocate a common household contribution proportionately to the # approved costs, preserving the household's total payable benefit. diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_initial_partial_month.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_initial_partial_month.py deleted file mode 100644 index 55ff91a3dfd..00000000000 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_initial_partial_month.py +++ /dev/null @@ -1,20 +0,0 @@ -from policyengine_us.model_api import * - - -class ia_ssa_ihhrc_initial_partial_month(Variable): - value_type = bool - entity = Person - label = "Iowa IHHRC initial partial month without client participation" - definition_period = MONTH - defined_for = StateCode.IA - default_value = False - documentation = "Set only for a first month of in-home health-related care service that is less than a full month, when no client participation is required. Key the entry to its month and enter the covered days in ia_ssa_care_partial_month_days." - reference = ( - "https://hhs.iowa.gov/media/3987/download?inline=#page=42", - # 441 IAC 177.8(2)"b" - "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=4", - ) - - def formula(person, period, parameters): - # A formula stops a one-month input from carrying into later months. - return False diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py index 526daa54451..a84c34430f5 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_monthly_cost.py @@ -7,5 +7,6 @@ class ia_ssa_ihhrc_monthly_cost(Variable): label = "Iowa SSA approved monthly in-home health-related care cost" definition_period = MONTH unit = USD + default_value = 0 reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=41" documentation = "Cost of the approved full-month service plan per recipient; care costing above the monthly ceiling is ineligible rather than capped. An entry carries into later months until it is changed." diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py index 93fc47de7cc..e75aba31f85 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py @@ -9,9 +9,11 @@ class ia_ssa_ihhrc_participation(Variable): unit = USD defined_for = StateCode.IA reference = ( - # 441 IAC 177.2(1)"f"-"g" and 177.8(2) + # 441 IAC 177.2(1)"f"-"g" and 177.8(2) (IAC 8/5/26) "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=1", - # PDF pages 41-43, 49 + # 441 IAC 177.4(1)"f"-"g" and 177.10(2) (IAC 2/5/25); PDF pages 2, 4-5 + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2", + # PDF pages 41-44, 49 "https://hhs.iowa.gov/media/3987/download?inline=#page=41", ) @@ -20,16 +22,36 @@ def formula(person, period, parameters): # couple standards ($994 and $1,491) and gives the couple allowance # "even if only one spouse receives in-home health-related care", so # the federal benefit rates are used and an SSI reform carries over. - # A child's marital unit has one member and receives the individual - # standard. + # A child has no spouse and receives the individual standard. ssi = parameters(period).gov.ssa.ssi income = person("ia_ssa_care_countable_income", period) deductions = max_(person("ia_ssa_care_additional_deductions", period), 0) - has_spouse = person.marital_unit.nb_persons() == 2 + has_spouse = person("ia_ssa_has_spouse", period) maintenance = where(has_spouse, ssi.amount.couple, ssi.amount.individual) deductions = where(has_spouse, person.marital_unit.sum(deductions), deductions) - participation = max_(income - maintenance - deductions, 0) + # 441 IAC 177.2(1)"f"(3) disregards "The amount of the SSI standard for + # a dependent plus any established unmet medical needs for each + # dependent living in the home. Any income of the dependent shall be + # applied to the dependent's needs before making this disregard." 6-B + # Home Maintenance Allowance (IHHRC) allows "$ 497 Maximum additional + # allowance for each dependent" less the dependent's income. SSI's + # ineligible child allocation is that amount, summed over the tax unit + # as in SSI spousal deeming. A child recipient's siblings are allowed in + # parental deeming instead (177.2(1)"g"(1)). + # NOTE: 6-B p.42 lists the "Home maintenance allowance for a single + # person, or for a couple if there is a spouse living with the client + # or a dependent living with an eligible person", with no deduction of + # the dependent's income. 441 IAC 177.2(1)"f"(3) applies "Any income of + # the dependent ... to the dependent's needs before making this + # disregard", as 6-B p.43 does ("Subtract a dependent's income"; Mr. B, + # 1,400 - 994 - 372 = 34). The model follows the rule and p.43 + # (ia_ssa.yaml Case 62). + head_or_spouse = person("is_tax_unit_head_or_spouse", period.this_year) + dependents = head_or_spouse * person.tax_unit.sum( + person("ssi_ineligible_child_allocation", period) + ) + participation = max_(income - maintenance - dependents - deductions, 0) # No client participation is required in a first partial month. return where( - person("ia_ssa_ihhrc_initial_partial_month", period), 0, participation + person("ia_ssa_care_initial_partial_month", period), 0, participation ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.py index fc723ddf75e..d2effd8c9ee 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_income_deemed_from_parents.py @@ -16,6 +16,8 @@ class ia_ssa_income_deemed_from_parents(Variable): "https://hhs.iowa.gov/media/3987/download?inline=#page=46", # 441 IAC 177.2(1)"g"(1) "https://www.legis.iowa.gov/docs/iac/chapter/441.177.pdf#page=2", + # 441 IAC 177.4(1)"g"(1) (IAC 2/5/25) + "https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf#page=2", ) def formula(person, period, parameters): @@ -53,6 +55,13 @@ def formula(person, period, parameters): # and 441 IAC 177 are silent on this case. allowance = where(parent_count > 1, ssi.amount.couple, ssi.amount.individual) pool_count = int(np.max(pool, initial=-1)) + 1 + # NOTE: 441 IAC 177.4(1)"g"(1)2 (IAC 2/5/25; 177.2(1)"g"(1)2 from + # October 1, 2026) disregards "The amount of the basic supplemental + # security income standard for a dependent for each ineligible child in + # the home". 6-B pp.47-49 allow a "maximum of $497 per child" and + # "Subtract any income of the dependent from the maximum deduction" + # (E family: $347 per child). The model follows the manual + # (ia_ssa_income_deemed_from_parents.yaml Case 3). # Each ineligible child of the same parents adds the SSI dependent # standard less that child's own income. sibling_allowance = np.bincount( diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py index d91d540494d..caf5e0d5eb9 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py @@ -9,7 +9,9 @@ class ia_ssa_nonfinancial_eligible(Variable): defined_for = StateCode.IA reference = ( # Iowa Code 249.3 - "https://www.legis.iowa.gov/docs/code/249.pdf#page=1", + "https://www.legis.iowa.gov/docs/code/249.pdf#page=2", + # 441 IAC 51.2 and 51.7(2); PDF pages 1-2 + "https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=1", # PDF pages 6, 8, 10-12 "https://hhs.iowa.gov/media/3987/download?inline=#page=6", ) @@ -30,6 +32,14 @@ def formula(person, period, parameters): # "an applicant must meet disability standards other than the inability # to engage in substantial gainful activity") is not modeled, because # is_ssi_disabled excludes people working above the SGA level. + # NOTE: Iowa Code 249.3(4)(a) limits the SMME supplement to a person + # "Sixty-five years of age or older" or "Disabled as defined by 42 + # U.S.C. §1382c(a)(3)". 441 IAC 51.7(2) requires "all eligibility + # requirements for supplemental security income benefits other than + # limits on substantial gainful activity and income", and 6-B p.76 + # starts from "the SSI eligibility requirements", which include + # blindness (p.10). The model follows 51.7(2) and the manual, so a + # blind person under 65 can receive SMME (ia_ssa.yaml Case 87). return ( person("is_ssi_aged_blind_disabled", period.this_year) & (citizen | immigrant) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_couple_budget.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_couple_budget.py new file mode 100644 index 00000000000..a03dba626d2 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_couple_budget.py @@ -0,0 +1,45 @@ +from policyengine_us.model_api import * + + +class ia_ssa_rcf_couple_budget(Variable): + value_type = bool + entity = Person + label = "Iowa SSA residential care couple budget in the month of entry" + definition_period = MONTH + defined_for = StateCode.IA + reference = ( + # 441 IAC 51.4(3); PDF pages 1-2 + "https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=1", + # PDF pages 60-61, 67-71 + "https://hhs.iowa.gov/media/3987/download?inline=#page=60", + ) + + def formula(person, period, parameters): + # 6-B Spouses Living Separately p.60: "When one or both spouses are + # receiving SSI before one or both enters an RCF, treat the spouses as + # a couple during the month of entry, then as individuals beginning the + # month after the month of entry", and "When neither spouse is + # receiving SSI before the entry of one or both into an RCF, treat the + # spouses separately beginning in the month of entry." 441 IAC 51.4(3) + # makes "Partners in a marriage who both enter the same room of the + # residential care facility in the same month" a couple for "the + # initial month"; spouses who both enter in the same month are taken + # to share a room (ia_ssa.yaml Cases 69, 71 and 72). A resident with an + # ineligible spouse is budgeted alone; SSI's first-month deemed income + # from that spouse (6-B p.60) is not modeled. + # NOTE: A spouse who enters after the other spouse's month of entry + # also gets the couple budget when either spouse received SSI, while + # the spouse already in the facility stays on the individual budget. 51.4(3) covers spouses who "both + # enter" in the same month, and p.61 makes a couple of spouses sharing + # a room "During their first month in the RCF", so neither settles a + # later entry. + category = person("ia_ssa_category", period) + rcf = category == category.possible_values.RESIDENTIAL_CARE + entering = rcf & person("ia_ssa_care_initial_partial_month", period) + couple = person("ssi_couple_computation_applies", period) & person( + "ia_ssa_has_spouse", period + ) + receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) + couple_received_ssi = person.marital_unit.any(receives_ssi) + both_enter = person.marital_unit.sum(entering) == 2 + return entering & couple & (couple_received_ssi | both_enter) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_daily_rate.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_daily_rate.py index dccd18794b3..d90dd9743af 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_daily_rate.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_daily_rate.py @@ -7,5 +7,10 @@ class ia_ssa_rcf_daily_rate(Variable): label = "Iowa SSA approved residential care daily rate" definition_period = MONTH unit = USD - reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=72" - documentation = "The per diem rate the department established for the facility; the model caps it at the maximum cost-related rate. Leave at 0 when no rate is approved. An entry carries into later months until it is changed." + default_value = 0 + reference = ( + # 441 IAC 52.1(3) + "https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1", + "https://hhs.iowa.gov/media/3987/download?inline=#page=72", + ) + documentation = "A per diem rate below the maximum that the department established for the facility. Leave at 0 to pay the maximum per diem rate, as 441 IAC 52.1(3) provides from July 1, 2017; an entry above the maximum is capped. An entry carries into later months until it is changed." diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py index 56ccba3f7d8..c41e5da95a4 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py @@ -13,8 +13,8 @@ class ia_ssa_resources_deemed_from_parents(Variable): unit = USD defined_for = StateCode.IA reference = ( - # PDF pages 12, 46-47 - "https://hhs.iowa.gov/media/3987/download?inline=#page=12", + # PDF pages 9, 12, 46-47 + "https://hhs.iowa.gov/media/3987/download?inline=#page=9", "https://www.ecfr.gov/current/title-20/section-416.1202#p-416.1202(b)", "https://www.ecfr.gov/current/title-20/section-416.1856", "https://secure.ssa.gov/poms.nsf/lnx/0501330200", @@ -33,8 +33,15 @@ class ia_ssa_resources_deemed_from_parents(Variable): # among the children of the same deemors who receive SSI or would # otherwise receive in-home health-related care, removing any child whose # own resources plus the share exceed the limit (SI 01330.200 and .280). - # Certified deeming exceptions and other state-only sibling eligibility - # are not modeled. + # 6-B p.9: "For an SSI recipient, accept the Social Security + # Administration's determination of SSI eligibility as verification that + # income, resources, and age, blindness or disability requirements have + # been met." The child test is is_ssi_resource_deeming_child, which + # applies SSA's exclusions (the 416.1202(b)(2) home-care exception, a + # medical treatment facility, a married or household-head minor). Iowa + # therefore deems only where SSA would, and in-home care children are + # deemed "in the same manner as SSI policy" (6-B p.46; ia_ssa.yaml Cases 80 + # and 83). Other state-only sibling eligibility is not modeled. def formula(person, period, parameters): limit = parameters(period).gov.ssa.ssi.eligibility.resources.limit @@ -45,11 +52,7 @@ def formula(person, period, parameters): ) allowance = where(parent_count > 1, limit.couple, limit.individual) excess = max_(parental_resources - allowance, 0) - child = ( - person("is_child", period.this_year) - & (person.marital_unit.nb_persons() == 1) - & ~person("is_household_head", period.this_year) - ) + child = person("is_ssi_resource_deeming_child", period) ihhrc = person("ia_ssa_nonfinancial_eligible", period) & ( person("ia_ssa_ihhrc_amount", period) > 0 ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py index e57b4480ffe..0a45416a534 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py @@ -8,8 +8,25 @@ class ia_ssa_smme_countable_income(Variable): definition_period = MONTH unit = USD defined_for = StateCode.IA - documentation = "SSI countable income plus any SSI payment. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." - reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=77" + documentation = "SSI countable income plus any SSI payment, combined for a couple whose SSI couple computation applies. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." + reference = ( + # 441 IAC 51.7(6) + "https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=2", + "https://hhs.iowa.gov/media/3987/download?inline=#page=77", + ) def formula(person, period, parameters): - return person("ssi_countable_income", period) + person("ssi", period) + # 6-B Income (SMME): income "is determined according to SSI income + # criteria", and 441 IAC 51.7(6) requires income that "must exceed 120 + # percent of the federal poverty level". ia_ssa uses the guideline for + # the recipient and any spouse (ia_ssa_has_spouse), so an eligible + # couple's combined income is compared with the two-person guideline + # (ia_ssa.yaml Cases 59-61). + # NOTE: With an ineligible spouse, SSI countable income includes only + # the income SSI deems from that spouse, and none when the spouse's + # income is at or below the deeming threshold, while the guideline is + # still for two people. Group-specific Medicaid budgeting is not + # modeled. + income = person("ssi_countable_income", period) + person("ssi", period) + joint = person("ssi_couple_computation_applies", period) + return where(joint, person.marital_unit.sum(income), income) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_coverage_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_coverage_eligible.py index a729e614e02..0cac605bf72 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_coverage_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_coverage_eligible.py @@ -6,5 +6,6 @@ class ia_ssa_smme_coverage_eligible(Variable): entity = Person label = "Iowa SMME full Medicaid and Medicare Part B requirements met" definition_period = MONTH + default_value = False reference = "https://hhs.iowa.gov/media/3987/download?inline=#page=76" documentation = "Receiving full Medicaid under a category independent of SSA without a premium or spenddown, and eligible for Medicare Part B. Ordinary Medicaid enrollment alone does not establish this status." From fb5eeee563fa2d192b4542468932af74de31f4a1 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 20 Oct 2026 20:06:49 -0400 Subject: [PATCH 27/33] Follow the Iowa Code for SMME and consolidate duplicate tests - SMME income qualifies at exactly 120 percent of the poverty guideline (Iowa Code 249.3(4)(g), "at least"), and SMME requires age 65 or disability (249.3(4)(a)); 441 IAC 51.7(6) and 51.7(2) read otherwise. Both follow the statute-first rule and are queued as source-conflict candidates. - Remove 12 test cases that repeated a kept case's branch and outcome, and retarget two boundary cases so they pin the comparison operator. - Update case citations in NOTEs. Co-Authored-By: Claude Opus 5.5 --- .../states/ia/hhs/ssa/ihhrc_cost_limit.yaml | 4 +- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 662 +++++++----------- .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 17 +- .../hhs/ssa/ia_ssa_care_countable_income.py | 7 +- .../gov/states/ia/hhs/ssa/ia_ssa_eligible.py | 2 +- .../gov/states/ia/hhs/ssa/ia_ssa_federal.py | 5 +- .../states/ia/hhs/ssa/ia_ssa_has_spouse.py | 2 +- .../ia/hhs/ssa/ia_ssa_ihhrc_participation.py | 2 +- .../hhs/ssa/ia_ssa_nonfinancial_eligible.py | 13 +- .../ia/hhs/ssa/ia_ssa_rcf_couple_budget.py | 6 +- .../ia_ssa_resources_deemed_from_parents.py | 8 +- .../hhs/ssa/ia_ssa_smme_countable_income.py | 9 +- 12 files changed, 293 insertions(+), 444 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml index 2af36c45eeb..7725a263712 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/ihhrc_cost_limit.yaml @@ -15,8 +15,8 @@ metadata: # $480.55 maximum benefit payable. The IAC 2/5/25 edition has it at # 177.11(4), citing 177.10(3). 177.2(1)"f" also limits countable income to # "$480.55 per month if one needs care or $961.10 if both need care", which - # pays nothing whenever participation reaches the cost (ia_ssa.yaml Cases - # 22-23). + # pays nothing whenever participation reaches the cost. ia_ssa.yaml Cases + # 16-17 pin the ceiling. reference: - title: Iowa HHS Employees' Manual 6-B (revised May 22, 2026), Income (IHHRC) href: https://hhs.iowa.gov/media/3987/download?inline=#page=41 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 121c10b7d3a..cab0916a067 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 @@ -9,45 +9,7 @@ output: ia_ssa: 0 -- name: Case 2, ordinary blind supplement. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - is_blind: true - output: - ia_ssa: 22 - -- name: Case 3, the Social Security Administration pays the blind supplement without federal SSI. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - is_blind: true - social_security_retirement: 12_240 - output: - # SSI: 1,020 - 20 = 1,000 > 994, so SSI is 0; 994 + 22 - 1,000 = 16. - ia_ssa: 16 - -- name: Case 4, dependent-person supplement. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - ia_ssa_category: DEPENDENT_PERSON - output: - ia_ssa: 518 - -- name: Case 5, blind dependent-person recipient. +- name: Case 2, blind dependent-person recipient. period: 2026-01 absolute_error_margin: 0.01 input: @@ -60,7 +22,7 @@ output: ia_ssa: 540 -- name: Case 6, dependent income at limit. +- name: Case 3, dependent income at limit. period: 2026-01 absolute_error_margin: 0.01 input: @@ -73,7 +35,7 @@ output: ia_ssa: 0 -- name: Case 7, dependent income is an eligibility gate not a grant deduction. +- name: Case 4, dependent income is an eligibility gate not a grant deduction. period: 2026-01 absolute_error_margin: 0.01 input: @@ -86,7 +48,7 @@ output: ia_ssa: 518 -- name: Case 8, total dependent group income exceeds standard. +- name: Case 5, total dependent group income exceeds standard. period: 2026-01 absolute_error_margin: 0.01 input: @@ -100,7 +62,7 @@ output: ia_ssa: 0 -- name: Case 9, family life home SSI-only top up. +- name: Case 6, family life home SSI-only top up. period: 2026-01 absolute_error_margin: 0.01 input: @@ -112,7 +74,7 @@ output: ia_ssa: 162 -- name: Case 10, blind family-life home stacks blind supplement. +- name: Case 7, blind family-life home stacks blind supplement. period: 2026-01 absolute_error_margin: 0.01 input: @@ -125,20 +87,7 @@ output: ia_ssa: 184 -- name: Case 11, family-life home with other unearned income. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - ia_ssa_category: FAMILY_LIFE_HOME - social_security_retirement: 1_200 - output: - ia_ssa: 142 - -- name: Case 12, family-life home earnings do not qualify for SSI-only top up. +- name: Case 8, family-life home earnings do not qualify for SSI-only top up. period: 2026-01 absolute_error_margin: 0.01 input: @@ -151,7 +100,7 @@ output: ia_ssa: 142 -- name: Case 13, the Social Security Administration pays the family-life home supplement without federal SSI. +- name: Case 9, the Social Security Administration pays the family-life home supplement without federal SSI. period: 2026-01 absolute_error_margin: 0.01 input: @@ -166,20 +115,7 @@ # 1,156, so SSA pays 142 - (1,080 - 994) = 56. ia_ssa: 56 -- name: Case 14, RCF actual January cost less participation. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - ia_ssa_category: RESIDENTIAL_CARE - ia_ssa_rcf_daily_rate: 38.47 - output: - ia_ssa: 328.57 - -- name: Case 15, RCF February uses actual days not eligibility multiplier. +- name: Case 10, RCF February uses actual days not eligibility multiplier. period: 2026-02 absolute_error_margin: 0.01 input: @@ -193,7 +129,7 @@ # February 2026 has 28 days: 38.47 * 28 = 1,077.16; 1,077.16 - 864 = 213.16. ia_ssa: 213.16 -- name: Case 16, blind RCF resident also gets blind supplement. +- name: Case 11, blind RCF resident also gets blind supplement. period: 2026-01 absolute_error_margin: 0.01 input: @@ -207,7 +143,7 @@ output: ia_ssa: 350.57 -- name: Case 17, RCF no general income disregard. +- name: Case 12, RCF no general income disregard. period: 2026-01 absolute_error_margin: 0.01 input: @@ -221,7 +157,7 @@ output: ia_ssa: 308.57 -- name: Case 18, RCF verified medical and family deductions. +- name: Case 13, RCF verified medical and family deductions. period: 2026-01 absolute_error_margin: 0.01 input: @@ -235,7 +171,7 @@ output: ia_ssa: 378.57 -- name: Case 19, RCF approved daily rate is capped. +- name: Case 14, RCF approved daily rate is capped. period: 2026-01 absolute_error_margin: 0.01 input: @@ -248,7 +184,7 @@ output: ia_ssa: 328.57 -- name: Case 20, RCF without a facility rate is paid at the maximum daily rate. +- name: Case 15, RCF without a facility rate is paid at the maximum daily rate. period: 2026-01 absolute_error_margin: 0.01 input: @@ -263,20 +199,7 @@ # 1,192.57 - 864 = 328.57. ia_ssa: 328.57 -- name: Case 21, in-home care at approved cost. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - ia_ssa_category: IN_HOME_CARE - ia_ssa_ihhrc_monthly_cost: 400 - output: - ia_ssa: 400 - -- name: Case 22, in-home care cost at ceiling. +- name: Case 16, in-home care cost at ceiling. period: 2026-01 absolute_error_margin: 0.01 input: @@ -289,7 +212,7 @@ output: ia_ssa: 480.55 -- name: Case 23, in-home cost over ceiling makes care ineligible. +- name: Case 17, in-home cost over ceiling makes care ineligible. period: 2026-01 absolute_error_margin: 0.01 input: @@ -302,7 +225,7 @@ output: ia_ssa: 0 -- name: Case 24, manual IHHRC example with social security and SSI. +- name: Case 18, manual IHHRC example with social security and SSI. period: 2026-01 absolute_error_margin: 0.01 input: @@ -318,53 +241,7 @@ ia_ssa_ihhrc_participation: 20 ia_ssa: 380 -- name: Case 25, IHHRC medical deductions reduce participation. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - ia_ssa_category: IN_HOME_CARE - ia_ssa_ihhrc_monthly_cost: 400 - social_security_retirement: 16_800 - ia_ssa_care_additional_deductions: 100 - output: - ia_ssa: 94 - -- name: Case 26, first partial in-home month has no participation. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - ia_ssa_category: IN_HOME_CARE - ia_ssa_ihhrc_monthly_cost: 400 - social_security_retirement: 16_800 - ia_ssa_care_partial_month_days: 16 - ia_ssa_care_initial_partial_month: true - output: - # No participation in the first partial month: 400 * 16 / 31 = 206.45. - ia_ssa: 206.45 - -- name: Case 27, blind allowance coexists with in-home care. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - ia_ssa_category: IN_HOME_CARE - ia_ssa_ihhrc_monthly_cost: 400 - is_blind: true - output: - ia_ssa: 422 - -- name: Case 28, excess resources. +- name: Case 19, excess resources. period: 2026-01 absolute_error_margin: 0.01 input: @@ -377,7 +254,7 @@ output: ia_ssa: 0 -- name: Case 29, nonresident. +- name: Case 20, nonresident. period: 2026-01 absolute_error_margin: 0.01 input: @@ -388,20 +265,7 @@ output: ia_ssa: 0 -- name: Case 30, opt out. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - is_blind: true - takes_up_ssi_if_eligible: false - output: - ia_ssa: 0 - -- name: Case 31, medical facility has no ordinary blind supplement. +- name: Case 21, medical facility has no ordinary blind supplement. period: 2026-01 absolute_error_margin: 0.01 input: @@ -414,21 +278,7 @@ output: ia_ssa: 0 -- name: Case 32, SMME requires full Medicaid and Part B. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - ia_ssa_category: SMME - ia_ssa_smme_coverage_eligible: true - ia_ssa_smme_countable_income: 2_000 - output: - ia_ssa: 1 - -- name: Case 33, SMME missing coverage. +- name: Case 22, SMME missing coverage. period: 2026-01 absolute_error_margin: 0.01 input: @@ -441,7 +291,7 @@ output: ia_ssa: 0 -- name: Case 34, SMME income below 120 percent poverty. +- name: Case 23, SMME income below 120 percent poverty. period: 2026-01 absolute_error_margin: 0.01 input: @@ -455,7 +305,7 @@ output: ia_ssa: 0 -- name: Case 35, SMME cannot stack with blind payment. +- name: Case 24, SMME cannot stack with blind payment. period: 2026-01 absolute_error_margin: 0.01 input: @@ -473,56 +323,7 @@ # Iowa 6-B IHHRC resource deeming and SSI sibling reallocation. # https://hhs.iowa.gov/media/3987/download?inline=#page=46 # https://secure.ssa.gov/poms.nsf/lnx/0501330280 -- name: Case 36, parental excess defeats the child resource test. - period: 2026-06 - absolute_error_margin: 0.01 - input: - people: - person1: - age: - 2026: 40 - person_id: - 2026: 1 - bank_account_assets: - 2026: 10_000 - person2: - age: - 2026: 10 - person_id: - 2026: 3 - parent_1_id: - 2026: 1 - ia_ssa_category: IN_HOME_CARE - ia_ssa_ihhrc_monthly_cost: 400 - is_disabled: - 2026: true - meets_ssi_disability_criteria: - 2026: true - marital_units: - parent1: - members: [person1] - child1: - members: [person2] - families: - family: - members: [person1, person2] - tax_units: - parent1: - members: [person1] - child1: - members: [person2] - spm_units: - unit: - members: [person1, person2] - households: - home: - members: [person1, person2] - state_code: - 2026: IA - output: - ia_ssa: [0, 0] - -- name: Case 37, one-parent allowance and child ceiling are inclusive. +- name: Case 25, one-parent allowance and child ceiling are inclusive. period: 2026-06 absolute_error_margin: 0.01 input: @@ -571,7 +372,7 @@ output: ia_ssa: [0, 400] -- name: Case 38, one cent above the combined allowances defeats eligibility. +- name: Case 26, one cent above the combined allowances defeats eligibility. period: 2026-06 absolute_error_margin: 0.01 input: @@ -620,7 +421,7 @@ output: ia_ssa: [0, 0] -- name: Case 39, an adult child does not receive deemed parental resources. +- name: Case 27, an adult child does not receive deemed parental resources. period: 2026-06 absolute_error_margin: 0.01 input: @@ -669,7 +470,7 @@ output: ia_ssa: [0, 400] -- name: Case 40, co-residence alone does not deem an unrelated adult resource balance. +- name: Case 28, co-residence alone does not deem an unrelated adult resource balance. period: 2026-06 absolute_error_margin: 0.01 input: @@ -729,7 +530,7 @@ output: ia_ssa: [0, 400, 0] -- name: Case 41, two eligible siblings share the same two-parent excess. +- name: Case 29, two eligible siblings share the same two-parent excess. period: 2026-06 absolute_error_margin: 0.01 input: @@ -810,7 +611,7 @@ output: ia_ssa: [0, 0, 400, 400] -- name: Case 42, an own-resource failure removes that sibling and reallocates the excess. +- name: Case 30, an own-resource failure removes that sibling and reallocates the excess. period: 2026-06 absolute_error_margin: 0.01 input: @@ -891,7 +692,7 @@ output: ia_ssa: [0, 0, 0, 0] -- name: Case 43, a linked parent outside the household is not a resource deemor. +- name: Case 31, a linked parent outside the household is not a resource deemor. period: 2026-06 absolute_error_margin: 0.01 input: @@ -948,7 +749,7 @@ output: ia_ssa: [0, 400] -- name: Case 44, partial in-home care days on one resident leave another resident's full month unchanged. +- name: Case 32, partial in-home care days on one resident leave another resident's full month unchanged. period: 2026-01 absolute_error_margin: 0.01 input: @@ -997,7 +798,7 @@ ia_ssa_ihhrc_amount: [206.45, 400] ia_ssa: [206.45, 400] -- name: Case 45, partial residential care days on one resident leave another resident's full month unchanged. +- name: Case 33, partial residential care days on one resident leave another resident's full month unchanged. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1042,7 +843,7 @@ # person2: 38.47 * 31 = 1,192.57 - 864 = 328.57. ia_ssa: [97.75, 328.57] -- name: Case 46, the initial partial-month flag and days apply only to the entry month. +- name: Case 34, the initial partial-month flag and days apply only to the entry month. period: 2026 absolute_error_margin: 0.01 input: @@ -1073,7 +874,7 @@ 2026-01: 206.45 2026-02: 0 -- name: Case 47, a one-month care deduction does not carry into the next month. +- name: Case 35, a one-month care deduction does not carry into the next month. period: 2026 absolute_error_margin: 0.01 input: @@ -1096,7 +897,7 @@ 2026-01: 94 2026-02: 0 -- name: Case 48, a residential care applicant over the SSI income limit need not take up SSI. +- name: Case 36, a residential care applicant over the SSI income limit need not take up SSI. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1115,7 +916,7 @@ ia_ssa_nonfinancial_eligible: true ia_ssa: 222.57 -- name: Case 49, an in-home care applicant over the SSI income limit need not take up SSI. +- name: Case 37, an in-home care applicant over the SSI income limit need not take up SSI. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1133,7 +934,7 @@ ia_ssa_ihhrc_participation: 106 ia_ssa: 294 -- name: Case 50, an SMME applicant over the SSI income limit need not take up SSI. +- name: Case 38, an SMME applicant over the SSI income limit need not take up SSI. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1151,7 +952,7 @@ ia_ssa_smme_countable_income: 1_980 ia_ssa: 1 -- name: Case 51, 2027 blind supplement. +- name: Case 39, 2027 blind supplement. period: 2027-01 absolute_error_margin: 0.01 input: @@ -1163,7 +964,7 @@ output: ia_ssa: 22 -- name: Case 52, 2027 residential care participation uses the 2027 SSI rate and personal needs allowance. +- name: Case 40, 2027 residential care participation uses the 2027 SSI rate and personal needs allowance. period: 2027-01 absolute_error_margin: 0.01 input: @@ -1180,7 +981,7 @@ # carried forward: 38.47 * 31 = 1,192.57 - 894 = 298.57. ia_ssa: 298.57 -- name: Case 53, 2027 family-life home standard follows the SSI rate. +- name: Case 41, 2027 family-life home standard follows the SSI rate. period: 2027-01 absolute_error_margin: 0.01 input: @@ -1195,7 +996,7 @@ # 1,156). With no other countable SSI income, SSA pays 162 - 20 = 142. ia_ssa_federal: 142 -- name: Case 54, 2027 family-life home income at the standard is ineligible. +- name: Case 42, 2027 family-life home income at the standard is ineligible. period: 2027-01 absolute_error_margin: 0.01 input: @@ -1212,7 +1013,7 @@ # either way. ia_ssa_federal: 0 -- name: Case 55, negative self-employment income does not inflate the residential care payment. +- name: Case 43, negative self-employment income does not inflate the residential care payment. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1227,7 +1028,7 @@ # Countable earnings floor at 0: SSI 994, participation 864, 1,192.57 - 864. ia_ssa: 328.57 -- name: Case 56, SMME income at 120 percent of poverty is not above the minimum. +- name: Case 44, SMME income at exactly 120 percent of poverty qualifies under Iowa Code 249.3(4)(g). period: 2026-01 absolute_error_margin: 0.01 input: @@ -1239,10 +1040,11 @@ ia_ssa_smme_coverage_eligible: true ia_ssa_smme_countable_income: 1_596 output: - # 1.2 * 15,960 / 12 = 1,596. - ia_ssa: 0 + # 1.2 * 15,960 / 12 = 1,596; the statute requires income "of at least" + # 120 percent, so 1,596 qualifies. + ia_ssa: 1 -- name: Case 57, SMME income one cent above 120 percent of poverty. +- name: Case 45, SMME income one cent below 120 percent of poverty. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1252,11 +1054,12 @@ 2026: 65 ia_ssa_category: SMME ia_ssa_smme_coverage_eligible: true - ia_ssa_smme_countable_income: 1_596.01 + ia_ssa_smme_countable_income: 1_595.99 output: - ia_ssa: 1 + # 1,595.99 is below 1.2 * 15,960 / 12 = 1,596, so no SMME. + ia_ssa: 0 -- name: Case 58, manual example excludes one-third of a child's child support from participation. +- name: Case 46, manual example excludes one-third of a child's child support from participation. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1312,11 +1115,12 @@ ia_ssa_ihhrc_participation: [0, 6] ia_ssa: [0, 394] -# 441 IAC 51.7(6) and 6-B Income (SMME) p.77: income "must exceed 120 percent -# of the federal poverty level". Case 59 is an aged couple with Social Security -# of $1,700 a month each; Cases 60-61 bracket the two-person threshold of +# Iowa Code 249.3(4)(g): income "of at least one hundred twenty percent of the +# federal poverty level" (441 IAC 51.7(6) and 6-B p.77 say "exceed"; the model +# follows the statute). Case 47 is an aged couple with Social Security of +# $1,700 a month each; Cases 48-49 bracket the two-person threshold of # 1.2 * (15,960 + 5,680) / 12 = 2,164. -- name: Case 59, an SMME couple's combined income is compared with the two-person guideline. +- name: Case 47, an SMME couple's combined income is compared with the two-person guideline. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1362,7 +1166,7 @@ ia_ssa_federal: [0, 0] ia_ssa: [1, 1] -- name: Case 60, an SMME couple just above the two-person guideline with one spouse covered. +- name: Case 48, an SMME couple just above the two-person guideline with one spouse covered. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1407,7 +1211,7 @@ ia_ssa_smme_countable_income: [2_166, 2_166] ia_ssa: [1, 0] -- name: Case 61, an SMME couple just below the two-person guideline. +- name: Case 49, an SMME couple just below the two-person guideline. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1444,7 +1248,7 @@ 2026: IA output: # SSI: 1,091 + 1,091 - 20 = 2,162 > 1,491, so SSI is 0; 2,162 / 2 = 1,081 - # each. SMME income 1,081 + 1,081 = 2,162 does not exceed 2,164. + # each. SMME income 1,081 + 1,081 = 2,162 is below 2,164. ssi_countable_income: [1_081, 1_081] ssi: [0, 0] ia_ssa_smme_countable_income: [2_162, 2_162] @@ -1453,7 +1257,7 @@ # 441 IAC 177.2(1)"f"(3) and 6-B Home Maintenance Allowance (IHHRC) p.43, # example 2: "Mr. B receives $1,400 in social security benefits; the child # receives $125." -- name: Case 62, manual IHHRC example deducts the dependent allowance less the child's income. +- name: Case 50, manual IHHRC example deducts the dependent allowance less the child's income. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1500,7 +1304,7 @@ # 6-B Client Participation for Adults (IHHRC) p.42: "The household consists # of the recipient, the recipient's spouse, and two children. The spouse has # earned income of $4,500." -- name: Case 63, manual IHHRC example with a working spouse and two children has no participation. +- name: Case 51, manual IHHRC example with a working spouse and two children has no participation. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1558,7 +1362,7 @@ # 441 IAC 52.1(3)"a"(6) and 6-B First-Month Client Participation p.63: "deduct # the SSI benefit rate for one person from the client's countable income". -- name: Case 64, a resident entering from home keeps income up to the SSI individual rate. +- name: Case 52, a resident entering from home keeps income up to the SSI individual rate. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1584,7 +1388,7 @@ # 441 IAC 52.1(3)"a"(6) and 6-B p.64: "If the client had a spouse living in # the home in the partial month before entry, deduct the SSI benefit rate for a # married couple". -- name: Case 65, a resident entering from a home shared with a spouse keeps income up to the SSI couple rate. +- name: Case 53, a resident entering from a home shared with a spouse keeps income up to the SSI couple rate. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1630,7 +1434,7 @@ # 441 IAC 51.5(2) and 6-B Resources p.12: "$3,000 for a married couple living # together"; "When the applicant is living with a spouse, count the spouse's # resources." -- name: Case 66, an in-home care couple within the couple resource limit. +- name: Case 54, an in-home care couple within the couple resource limit. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1672,7 +1476,7 @@ ia_ssa_ihhrc_participation: [0, 0] ia_ssa: [400, 0] -- name: Case 67, an in-home care couple over the couple resource limit. +- name: Case 55, an in-home care couple over the couple resource limit. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1710,7 +1514,7 @@ ia_ssa_eligible: [false, false] ia_ssa: [0, 0] -- name: Case 68, RCF with an entered facility rate below the maximum. +- name: Case 56, RCF with an entered facility rate below the maximum. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1728,7 +1532,7 @@ # 6-B Resource and Income Guidelines for Married Couples pp.60-61 and Client # Participation pp.68-71: spouses who received SSI are a couple in the month # one enters a residential care facility and individuals from the month after. -- name: Case 69, manual example where a resident whose spouse stays home is budgeted alone after the entry month. +- name: Case 57, manual example where a resident whose spouse stays home is budgeted alone after the entry month. period: 2026 absolute_error_margin: 0.01 input: @@ -1781,7 +1585,7 @@ # 441 IAC 51.4(3) and 6-B Spouses Sharing a Room p.61: "After the month of # entry, treat the spouses as individuals when determining eligibility and # client participation." -- name: Case 70, spouses sharing a room are budgeted as individuals after the entry month. +- name: Case 58, spouses sharing a room are budgeted as individuals after the entry month. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1827,7 +1631,7 @@ # residential care facility in the same month will be income eligible for the # initial month when their combined income ... is less than twice the amount of # allowed income for one person". -- name: Case 71, spouses entering the same room in the same month are budgeted as a couple. +- name: Case 59, spouses entering the same room in the same month are budgeted as a couple. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1878,7 +1682,7 @@ # 6-B p.60: "When neither spouse is receiving SSI before the entry of one or # both into an RCF, treat the spouses separately beginning in the month of # entry"; p.61: the resident "must now apply for and accept SSI benefits". -- name: Case 72, manual example where spouses without SSI are budgeted separately from the entry month. +- name: Case 60, manual example where spouses without SSI are budgeted separately from the entry month. period: 2026 absolute_error_margin: 0.01 input: @@ -1926,62 +1730,9 @@ 2026-05: [769.4, 0] 2026-06: [270.1, 0] -- name: Case 73, manual example of an SSI resident with an ineligible working spouse after the entry month. - period: 2026 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 70 - # 6-B p.67 Mr. A: Social Security of $200 a month. - social_security_retirement: 2_400 - ia_ssa_category: - 2026-06: RESIDENTIAL_CARE - 2026-07: RESIDENTIAL_CARE - # 6-B gives only the month; entry is taken as June 15, so June 15 - # through 30 are covered. - ia_ssa_care_partial_month_days: - 2026-06: 16 - ia_ssa_care_initial_partial_month: - 2026-06: true - # 6-B p.68: "Diversion for Mrs. A (994 - 457.50 ...)". - ia_ssa_care_additional_deductions: - 2026-07: 536.5 - person2: - age: 60 - # Mrs. A: earnings of $1,000 a month. - employment_income: 12_000 - marital_units: - couple: - 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: - # June: SSI with spousal deeming 1,491 - 647.50 = 843.50 (6-B p.67). Mrs. A - # is not aged, blind or disabled, so there is no couple budget. Care income - # 200 + 843.50 = 1,043.50; entry deduction 1,491 (spouse at home); - # participation max(1,043.50 - 130 - 1,491, 0) = 0, as on p.67; - # 38.47 * 16 = 615.52. First-month deemed spouse income is not modeled. - # July: SSI as an individual 994 - (200 - 20) = 814 (6-B p.68); care - # income 1,014; participation 1,014 - 130 - 536.50 = 347.50 (6-B p.68); - # 38.47 * 31 = 1,192.57 - 347.50 = 845.07. - ssi: - 2026-06: [843.5, 0] - ia_ssa: - 2026-06: [615.52, 0] - 2026-07: [845.07, 0] - # 6-B Resources p.12: "When the applicant is not living with the spouse, do not # count the spouse's resources." -- name: Case 74, a resident's resources are tested alone after the entry month. +- name: Case 61, a resident's resources are tested alone after the entry month. period: 2026-01 absolute_error_margin: 0.01 input: @@ -1989,7 +1740,7 @@ person1: age: 2026: 70 - # $2,500 of resources, the reviewer's figure in Cases 66-67. + # $2,500 of resources, the reviewer's figure in Cases 54-55. ssi_countable_resources: 2026: 2_500 ia_ssa_category: RESIDENTIAL_CARE @@ -2022,7 +1773,7 @@ # 441 IAC 52.1(3)"a"(1) deducts "impairment-related work expenses, as defined # by SSI plus $65 plus one-half of any remaining earned income"; 6-B p.65 Mr. L # has earnings of $333 and expenses of $100. -- name: Case 75, a resident without SSI enters impairment-related work expenses at one-half. +- name: Case 62, a resident without SSI enters impairment-related work expenses at one-half. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2049,31 +1800,10 @@ ia_ssa_care_countable_income: 1_234 ia_ssa: 138.57 -# 20 CFR 416.1124(c)(22) excludes "Interest and dividend income from a -# countable resource"; Manual 8-E Dividends p.23 and Interest Income p.36. -- name: Case 76, a resident's interest is excluded from care income. - period: 2026-01 - absolute_error_margin: 0.01 - input: - state_code: - 2026: IA - age: - 2026: 65 - # Reviewer example: $5 a month of interest on savings. - interest_income: - 2026: 60 - ia_ssa_category: RESIDENTIAL_CARE - output: - # SSI: the $20 general exclusion covers the $5, so SSI is 994. Care income - # 0 + 994 = 994; participation 864; 1,192.57 - 864 = 328.57. - ssi: 994 - ia_ssa_care_countable_income: 994 - ia_ssa: 328.57 - # 6-B Making the Family-Life Home Payment p.35: "For a recipient who has only # SSI and no other income (and hence no $20 to disregard), an additional $20 # payment is necessary". -- name: Case 77, a family-life home resident whose only other income is interest gets the 20 dollar payment. +- name: Case 63, a family-life home resident whose only other income is interest gets the 20 dollar payment. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2092,7 +1822,7 @@ ia_ssa_federal: 142 ia_ssa: 162 -- name: Case 78, a family-life home resident with 10 dollars of Social Security gets no 20 dollar payment. +- name: Case 64, a family-life home resident with 10 dollars of Social Security gets no 20 dollar payment. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2112,7 +1842,7 @@ ia_ssa_federal: 142 ia_ssa: 142 -- name: Case 79, without marital units an in-home care parent is not paired with an adult child. +- name: Case 65, without marital units an in-home care parent is not paired with an adult child. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2158,61 +1888,9 @@ ia_ssa_ihhrc_participation: [20, 0] ia_ssa: [380, 0] -# 6-B Deeming Parents' Resources p.47 Child B: "$ 5,500 Parent's resources - -# 3,000 Exempt $ 2,500 Deemed to Child B". -- name: Case 80, without marital units parental resources are still deemed to an in-home care child. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: - 2026: 40 - person_id: - 2026: 1 - bank_account_assets: - 2026: 5_500 - person2: - age: - 2026: 40 - person_id: - 2026: 2 - person3: - age: - 2026: 10 - person_id: - 2026: 3 - parent_1_id: - 2026: 1 - parent_2_id: - 2026: 2 - ia_ssa_category: IN_HOME_CARE - ia_ssa_ihhrc_monthly_cost: 400 - is_disabled: - 2026: true - meets_ssi_disability_criteria: - 2026: true - tax_units: - tax_unit: - members: [person1, person2, person3] - spm_units: - spm_unit: - members: [person1, person2, person3] - households: - household: - members: [person1, person2, person3] - state_code: - 2026: IA - output: - # The three people share one default marital unit, which is not a couple. - # The parent links give two parents, so the allowance is 3,000: - # 5,500 - 3,000 = 2,500 deemed to the child exceeds 2,000. - ia_ssa_resources_deemed_from_parents: [0, 0, 2_500] - ia_ssa: [0, 0, 0] - # SI 02001.005 and SI 02001.010: SSA drops digits beyond the third decimal, # rounds up to the cent and pays at least $1. -- name: Case 81, a blind supplement of 50 cents is paid at the 1 dollar minimum. +- name: Case 66, a blind supplement of 50 cents is paid at the 1 dollar minimum. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2231,7 +1909,7 @@ ia_ssa_federal: 1 ia_ssa: 1 -- name: Case 82, a blind supplement is rounded up to the cent. +- name: Case 67, a blind supplement is rounded up to the cent. period: 2026-01 absolute_error_margin: 0.001 input: @@ -2254,7 +1932,7 @@ # income, resources, and age, blindness or disability requirements have been # met." 20 CFR 416.1202(b)(2) waives parental resource deeming for some # children in Medicaid home care. -- name: Case 83, a blind SSI child exempt from parental resource deeming keeps the blind supplement. +- name: Case 68, a blind SSI child exempt from parental resource deeming keeps the blind supplement. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2310,7 +1988,7 @@ # 441 IAC 51.4(3): income eligible when income "is less than 31 times the # maximum per diem rate". -- name: Case 84, residential care participation equal to the month's cost pays nothing. +- name: Case 69, residential care participation equal to the month's cost pays nothing. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2329,7 +2007,7 @@ # 6-B Income (DP) p.25: group income "must be less than the applicable # assistance standard", 994 + 518 = 1,512 for one person. -- name: Case 85, dependent-person group income one cent below the standard pays the 1 dollar minimum. +- name: Case 70, dependent-person group income one cent below the standard pays the 1 dollar minimum. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2347,7 +2025,7 @@ ia_ssa_federal: 1 ia_ssa: 1 -- name: Case 86, dependent-person group income at the standard is ineligible. +- name: Case 71, dependent-person group income at the standard is ineligible. period: 2026-01 absolute_error_margin: 0.01 input: @@ -2355,20 +2033,24 @@ 2026: IA age: 2026: 65 - # Reviewer boundary income: 1,532 a month. + # Social Security of $1,492 a month, so SSI countable income is 1,472. social_security_retirement: - 2026: 18_384 + 2026: 17_904 ia_ssa_category: DEPENDENT_PERSON + ia_ssa_dependent_countable_income: 40 output: - # 1,532 - 20 = 1,512 is not less than 1,512. + # Group income 1,472 + 40 = 1,512 is not less than the 994 + 518 = 1,512 + # standard (6-B p.25, "less than"), so nothing is paid. Without the gate + # the supplement would be 518 - (1,472 - 994) = 40. + ssi: 0 ia_ssa_federal: 0 ia_ssa: 0 # Iowa Code 249.3(4)(a) names a person 65 or older or disabled; 441 IAC 51.7(2) # requires "all eligibility requirements for supplemental security income # benefits other than limits on substantial gainful activity and income", which -# include blindness (6-B pp.10, 76). The model follows 51.7(2). -- name: Case 87, a blind SMME applicant under 65 qualifies under 441 IAC 51.7(2). +# include blindness (6-B pp.10, 76). The model follows the statute. +- name: Case 72, a blind SMME applicant under 65 who is not disabled does not qualify under Iowa Code 249.3(4)(a). period: 2026-01 absolute_error_margin: 0.01 input: @@ -2378,16 +2060,168 @@ 2026: 50 is_blind: 2026: true - # SSDI of $2,020 a month, above the blind SSI limit and 120 percent of - # poverty. - social_security_disability: + # A pension of $2,020 a month, above the blind SSI limit and 120 percent + # of poverty. + pension_income: 2026: 24_240 ia_ssa_category: SMME ia_ssa_smme_coverage_eligible: true output: # SSI countable income 2,020 - 20 = 2,000 exceeds both 994 and the blind - # limit of 1,016, so SSI and the blind supplement are 0. SMME income 2,000 - # exceeds 1.2 * 15,960 / 12 = 1,596. + # limit of 1,016, so SSI and the blind supplement are 0. Iowa Code + # 249.3(4)(a) admits only a person 65 or older or disabled, so this blind + # 50-year-old gets no SMME. + ssi: 0 + ia_ssa_federal: 0 + ia_ssa_nonfinancial_eligible: false + ia_ssa: 0 + +- name: Case 73, manual example of an SSI resident with an ineligible working spouse after the entry month. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # 6-B p.67 Mr. A: Social Security of $200 a month. + social_security_retirement: 2_400 + ia_ssa_category: + 2026-06: RESIDENTIAL_CARE + 2026-07: RESIDENTIAL_CARE + # 6-B gives only the month; entry is taken as June 15, so June 15 + # through 30 are covered. + ia_ssa_care_partial_month_days: + 2026-06: 16 + ia_ssa_care_initial_partial_month: + 2026-06: true + # 6-B p.68: "Diversion for Mrs. A (994 - 457.50 ...)". + ia_ssa_care_additional_deductions: + 2026-07: 536.5 + person2: + age: 60 + # Mrs. A: earnings of $1,000 a month. + employment_income: 12_000 + marital_units: + couple: + 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: + # June: SSI with spousal deeming 1,491 - 647.50 = 843.50 (6-B p.67). Mrs. A + # is not aged, blind or disabled, so there is no couple budget. Care income + # 200 + 843.50 = 1,043.50; entry deduction 1,491 (spouse at home); + # participation max(1,043.50 - 130 - 1,491, 0) = 0, as on p.67; + # 38.47 * 16 = 615.52. First-month deemed spouse income is not modeled. + # July: SSI as an individual 994 - (200 - 20) = 814 (6-B p.68); care + # income 1,014; participation 1,014 - 130 - 536.50 = 347.50 (6-B p.68); + # 38.47 * 31 = 1,192.57 - 347.50 = 845.07. + ssi: + 2026-06: [843.5, 0] + ia_ssa: + 2026-06: [615.52, 0] + 2026-07: [845.07, 0] + +# 20 CFR 416.1124(c)(22) excludes "Interest and dividend income from a +# countable resource"; Manual 8-E Dividends p.23 and Interest Income p.36. +- name: Case 74, a resident's interest is excluded from care income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + # Reviewer example: $5 a month of interest on savings. + interest_income: + 2026: 60 + ia_ssa_category: RESIDENTIAL_CARE + output: + # SSI: the $20 general exclusion covers the $5, so SSI is 994. Care income + # 0 + 994 = 994; participation 864; 1,192.57 - 864 = 328.57. + ssi: 994 + ia_ssa_care_countable_income: 994 + ia_ssa: 328.57 + +# 6-B Deeming Parents' Resources p.47 Child B: "$ 5,500 Parent's resources - +# 3,000 Exempt $ 2,500 Deemed to Child B". +- name: Case 75, without marital units parental resources are still deemed to an in-home care child. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 40 + person_id: + 2026: 1 + bank_account_assets: + 2026: 5_500 + person2: + age: + 2026: 40 + person_id: + 2026: 2 + person3: + age: + 2026: 10 + person_id: + 2026: 3 + parent_1_id: + 2026: 1 + parent_2_id: + 2026: 2 + ia_ssa_category: IN_HOME_CARE + ia_ssa_ihhrc_monthly_cost: 400 + is_disabled: + 2026: true + meets_ssi_disability_criteria: + 2026: true + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2026: IA + output: + # The three people share one default marital unit, which is not a couple. + # The parent links give two parents, so the allowance is 3,000: + # 5,500 - 3,000 = 2,500 deemed to the child exceeds 2,000. + ia_ssa_resources_deemed_from_parents: [0, 0, 2_500] + ia_ssa: [0, 0, 0] + +- name: Case 76, a blind SMME applicant under 65 who is also disabled qualifies. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 50 + is_blind: + 2026: true + meets_ssi_disability_criteria: + 2026: true + # SSDI of $2,020 a month, above the SSI limits and 120 percent of poverty. + social_security_disability: + 2026: 24_240 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + output: + # Disabled under 42 U.S.C. 1382c(a)(3), so 249.3(4)(a) is met. SMME income + # 2,020 - 20 = 2,000 exceeds 1.2 * 15,960 / 12 = 1,596. ssi: 0 ia_ssa_federal: 0 ia_ssa_smme_countable_income: 2_000 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 edd5dda7bbd..1e077b5fb58 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 @@ -39,7 +39,7 @@ def formula(person, period, parameters): # specifically for each facility" of up to $38.47, or "A flat per diem # rate ... $17.86 beginning February 1, 2004". The model follows the # rule and pays the maximum rate unless a lower facility rate is - # entered (ia_ssa.yaml Cases 19, 20 and 68). + # entered (ia_ssa.yaml Cases 14, 15 and 56). entered_rate = max_(person("ia_ssa_rcf_daily_rate", period), 0) rate = where( entered_rate > 0, @@ -59,7 +59,7 @@ def formula(person, period, parameters): # "keep enough of the first month's income to meet maintenance or # living expenses from the previous living arrangement, but do not # disregard an amount that is over the SSI standard". The model follows - # the rule's fixed amount (ia_ssa.yaml Cases 64-65). + # the rule's fixed amount (ia_ssa.yaml Cases 52-53). has_spouse = person("ia_ssa_has_spouse", period) entry = where(has_spouse, federal.amount.couple, federal.amount.individual) entry = where( @@ -80,7 +80,7 @@ def formula(person, period, parameters): sources = federal.income.sources # Interest and dividends are excluded from income as in # ia_ssa_care_countable_income (20 CFR 416.1124(c)(22)), so they are - # not other income here (ia_ssa.yaml Case 77). + # not other income here (ia_ssa.yaml Case 63). excluded = p.excluded_unearned_sources has_other_income = np.zeros(person.count, dtype=bool) for source in list(sources.earned) + list(sources.unearned): @@ -108,17 +108,18 @@ def formula(person, period, parameters): + (size - 1) * fpg.additional_person.CONTIGUOUS_US ) / MONTHS_IN_YEAR # NOTE: Iowa Code 249.3(4)(g) requires "income of at least one hundred - # twenty percent of the federal poverty level", in a subsection that - # opens "At the discretion of the department". 441 IAC 51.7(6) says + # twenty percent of the federal poverty level". 441 IAC 51.7(6) says # income "must exceed 120 percent of the federal poverty level", and # 6-B Income (SMME) p.77 says it "also exceeds 120% of the federal - # poverty level". The model follows 51.7(6) and the manual, so income - # of exactly 120% does not qualify (ia_ssa.yaml Cases 56-57). + # poverty level". Where a statute and a rule or manual disagree, the + # model follows the statute (the statute-first rule in CONTRIBUTING.md), so + # income of exactly 120% qualifies and one cent less does not + # (ia_ssa.yaml Cases 44-45). smme = ( person("ia_ssa_smme_coverage_eligible", period) & ( person("ia_ssa_smme_countable_income", period) - > p.smme_minimum_fpg_rate * poverty + >= p.smme_minimum_fpg_rate * poverty ) & (federally_paid == 0) ) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py index 86596449aa9..087810af14f 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_care_countable_income.py @@ -39,7 +39,7 @@ def formula(person, period, parameters): # earned income" (6-B p.65, Mr. L). Neither federal SSI nor this # variable models those expenses (issue 3669). For a resident without # SSI, entering one-half of them in ia_ssa_care_additional_deductions - # reproduces the rule (ia_ssa.yaml Case 75). For an SSI recipient, + # reproduces the rule (ia_ssa.yaml Case 62). For an SSI recipient, # SSA's payment rises by the same one-half, so care income does not # change (6-B p.59). earned = max_( @@ -51,7 +51,8 @@ def formula(person, period, parameters): # from a countable resource", as Manual 8-E Dividends and Interest # Income do. Federal SSI still counts them (issue 10079), so the # sources in excluded_unearned_sources are dropped here and from the - # family-life home $20 test in ia_ssa (ia_ssa.yaml Cases 76-77). + # family-life home $20 test in ia_ssa (ia_ssa.yaml Case 74 for + # residential care income and Case 63 for the $20 test). # Remove the list once issue 10079 is fixed, or they are excluded # twice. SMME income (ia_ssa_smme_countable_income) and the SSA-paid # amounts (ia_ssa_federal) use SSI countable income, so they count @@ -86,7 +87,7 @@ def formula(person, period, parameters): # resident who does not take up SSI. Federal SSI has no input for # spouses who live apart and keeps the couple or deemed amount, so the # SSI individual amount is computed here from the resident's own income - # (ia_ssa.yaml Cases 69-73). + # (ia_ssa.yaml Cases 57, 58, 60 and 73). individual_ssi = max_( ssi.amount.individual - _apply_ssi_exclusions( 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 d4b6d53776b..9bdb207b59b 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 @@ -32,7 +32,7 @@ def formula(person, period, parameters): # the spouse, do not count the spouse's resources." A residential care # resident lives apart from the spouse after the month of entry (6-B # p.60), so only the couple-budget entry month pools resources - # (ia_ssa.yaml Case 74). + # (ia_ssa.yaml Case 61). # NOTE: The spouse who stays at home still pools resources with the # resident after the month of entry, though p.12 would test that # spouse alone. Federal SSI in the model has no input for spouses who diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py index af595815156..74780fa9109 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_federal.py @@ -54,7 +54,7 @@ def formula(person, period, parameters): # exactly $518. 6-B p.25 ("The dependent must have countable income of # less than $518 per month") and 441 IAC 51.5(1) ("must be less than # the amount established by the department") exclude it. The model - # follows 51.5(1) and p.25 (ia_ssa.yaml Case 6). + # follows 51.5(1) and p.25 (ia_ssa.yaml Case 3). # The dependent-person standards are couple standards (441 IAC # 52.1(2)"b", "d" and "e"), so certifying either spouse of an eligible # couple applies the couple level (integration.yaml Cases 11-12), @@ -89,7 +89,8 @@ def formula(person, period, parameters): # in any other State living arrangement variation", the SSA-coded # dependent-person and family-life home rows, whose levels include the # $22. The model follows the manual and POMS and pays the $22 with - # residential care and in-home care (ia_ssa.yaml Cases 16 and 27). + # residential care (ia_ssa.yaml Case 11) and in-home care + # (integration.yaml Case 9). individual_rate = ( dp * p.dependent_amount + flh * family_life_individual diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_has_spouse.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_has_spouse.py index d1da130610a..a5b4b549cd7 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_has_spouse.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_has_spouse.py @@ -20,7 +20,7 @@ def formula(person, period, parameters): # count the spouse's resources." A two-person marital unit is a couple # only when SSI's spouse test pairs its members, so the default unit of # a situation without marital units does not pair a parent with an - # adult child the parent claims (ia_ssa.yaml Case 79). A default unit + # adult child the parent claims (ia_ssa.yaml Case 65). A default unit # of three or more people budgets each member alone. couple_unit = person.marital_unit.nb_persons() == 2 return couple_unit & (_ssi_spouse_index(person, period) >= 0) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py index e75aba31f85..08130590781 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_ihhrc_participation.py @@ -45,7 +45,7 @@ def formula(person, period, parameters): # the dependent ... to the dependent's needs before making this # disregard", as 6-B p.43 does ("Subtract a dependent's income"; Mr. B, # 1,400 - 994 - 372 = 34). The model follows the rule and p.43 - # (ia_ssa.yaml Case 62). + # (ia_ssa.yaml Case 50). head_or_spouse = person("is_tax_unit_head_or_spouse", period.this_year) dependents = head_or_spouse * person.tax_unit.sum( person("ssi_ineligible_child_allocation", period) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py index caf5e0d5eb9..6b4909e4f23 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py @@ -38,10 +38,17 @@ def formula(person, period, parameters): # requirements for supplemental security income benefits other than # limits on substantial gainful activity and income", and 6-B p.76 # starts from "the SSI eligibility requirements", which include - # blindness (p.10). The model follows 51.7(2) and the manual, so a - # blind person under 65 can receive SMME (ia_ssa.yaml Case 87). + # blindness (p.10). Where a statute and a rule or manual disagree, the + # model follows the statute (the statute-first rule in CONTRIBUTING.md), so a + # blind person under 65 who is not disabled gets no SMME, while one who + # is disabled does (ia_ssa.yaml Cases 72 and 76). + aged_blind_disabled = person("is_ssi_aged_blind_disabled", period.this_year) + aged_or_disabled = person("is_ssi_aged", period.this_year) | person( + "is_ssi_disabled", period.this_year + ) + smme = category == category.possible_values.SMME return ( - person("is_ssi_aged_blind_disabled", period.this_year) + where(smme, aged_or_disabled, aged_blind_disabled) & (citizen | immigrant) & (category != category.possible_values.NONE) & ~person("is_incarcerated", period) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_couple_budget.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_couple_budget.py index a03dba626d2..25173adcd27 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_couple_budget.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_rcf_couple_budget.py @@ -24,9 +24,9 @@ def formula(person, period, parameters): # makes "Partners in a marriage who both enter the same room of the # residential care facility in the same month" a couple for "the # initial month"; spouses who both enter in the same month are taken - # to share a room (ia_ssa.yaml Cases 69, 71 and 72). A resident with an - # ineligible spouse is budgeted alone; SSI's first-month deemed income - # from that spouse (6-B p.60) is not modeled. + # to share a room (ia_ssa.yaml Cases 57, 59 and 60). A resident with an + # ineligible spouse is budgeted alone (ia_ssa.yaml Case 73); SSI's + # first-month deemed income from that spouse (6-B p.60) is not modeled. # NOTE: A spouse who enters after the other spouse's month of entry # also gets the couple budget when either spouse received SSI, while # the spouse already in the facility stays on the individual budget. 51.4(3) covers spouses who "both diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py index c41e5da95a4..7ffa7cf73c7 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_deemed_from_parents.py @@ -39,9 +39,11 @@ class ia_ssa_resources_deemed_from_parents(Variable): # been met." The child test is is_ssi_resource_deeming_child, which # applies SSA's exclusions (the 416.1202(b)(2) home-care exception, a # medical treatment facility, a married or household-head minor). Iowa - # therefore deems only where SSA would, and in-home care children are - # deemed "in the same manner as SSI policy" (6-B p.46; ia_ssa.yaml Cases 80 - # and 83). Other state-only sibling eligibility is not modeled. + # therefore deems only where SSA would (ia_ssa.yaml Case 68), and in-home + # care children are deemed "in the same manner as SSI policy" (6-B p.46; + # ia_ssa_resources_deemed_from_parents.yaml Case 7; without marital units, + # ia_ssa.yaml Case 75). Other state-only + # sibling eligibility is not modeled. def formula(person, period, parameters): limit = parameters(period).gov.ssa.ssi.eligibility.resources.limit diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py index 0a45416a534..78b1f1075ee 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py @@ -10,6 +10,8 @@ class ia_ssa_smme_countable_income(Variable): defined_for = StateCode.IA documentation = "SSI countable income plus any SSI payment, combined for a couple whose SSI couple computation applies. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." reference = ( + # Iowa Code 249.3(4)(g) + "https://www.legis.iowa.gov/docs/code/249.pdf#page=2", # 441 IAC 51.7(6) "https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=2", "https://hhs.iowa.gov/media/3987/download?inline=#page=77", @@ -17,11 +19,12 @@ class ia_ssa_smme_countable_income(Variable): def formula(person, period, parameters): # 6-B Income (SMME): income "is determined according to SSI income - # criteria", and 441 IAC 51.7(6) requires income that "must exceed 120 - # percent of the federal poverty level". ia_ssa uses the guideline for + # criteria". ia_ssa compares it with 120 percent of the poverty + # guideline as Iowa Code 249.3(4)(g) sets it ("at least"; see the NOTE + # in ia_ssa). ia_ssa uses the guideline for # the recipient and any spouse (ia_ssa_has_spouse), so an eligible # couple's combined income is compared with the two-person guideline - # (ia_ssa.yaml Cases 59-61). + # (ia_ssa.yaml Cases 47-49). # NOTE: With an ineligible spouse, SSI countable income includes only # the income SSI deems from that spouse, and none when the spouse's # income is at or below the deeming threshold, while the guideline is From 040662b00399713c93faabafc06b846eae6cd368 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 21 Oct 2026 00:55:41 -0400 Subject: [PATCH 28/33] List Iowa's two SMME statute conflicts as source-conflict candidates The model follows Iowa Code 249.3(4)(g) and (4)(a) over 441 IAC 51.7(6) and 51.7(2); the entries wait in source_conflicts/candidates.yaml until they are registered. Co-Authored-By: Claude Opus 5.5 --- source_conflicts/candidates.yaml | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 7d8c41658c6..5b70dc049e8 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -1775,6 +1775,68 @@ candidates: state: ruled note: 'Ruled statute-first in October 2026; the rule requires replacing the approximation using claimant inputs, with annual verification because the supplied statutory URL is for 2026. Code not yet on main: ia_is_tax_exempt.' +- id: us-ia:smme-blind-under-65 + program: ssi-state-supplement + years: + from: 2026 + to: 2026 + type: calendar + question: Can a blind person under 65 who is not disabled receive Iowa's supplement for people with medical + expenses (SMME)? + sources: + - kind: statute + citation: Iowa Code 249.3(4)(a) + url: https://www.legis.iowa.gov/docs/code/249.pdf#page=2 + - kind: regulation + citation: 441 IAC 51.7(2) + url: https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=2 + - kind: manual + citation: Iowa HHS Employees' Manual 6-B, SMME and SSI eligibility requirements + url: https://hhs.iowa.gov/media/3987/download?inline=#page=76 + readings: + statute: Only a person "Sixty-five years of age or older" or "Disabled as defined by 42 U.S.C. §1382c(a)(3)" + qualifies, so blindness alone does not. + other: The rule requires "all eligibility requirements for supplemental security income benefits other than + limits on substantial gainful activity and income", which include blindness. + example: A blind 50-year-old with a $2,020 monthly pension and SMME coverage gets $0 under the statute and $1 + under the rule. + pe_us: + follows: statute + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/8017 + state: ruled + note: 'Code not yet on main: ia_ssa_nonfinancial_eligible.' +- id: us-ia:smme-income-at-least-120-percent + program: ssi-state-supplement + years: + from: 2026 + to: 2026 + type: calendar + question: Does Iowa's SMME supplement require income of at least, or more than, 120 percent of the poverty + guideline? + sources: + - kind: statute + citation: Iowa Code 249.3(4)(g) + url: https://www.legis.iowa.gov/docs/code/249.pdf#page=2 + - kind: regulation + citation: 441 IAC 51.7(6) + url: https://www.legis.iowa.gov/docs/iac/chapter/441.51.pdf#page=2 + - kind: manual + citation: Iowa HHS Employees' Manual 6-B, Income (SMME) + url: https://hhs.iowa.gov/media/3987/download?inline=#page=77 + readings: + statute: Income "of at least one hundred twenty percent of the federal poverty level" qualifies. + other: Income "must exceed 120 percent of the federal poverty level". + example: A single applicant with countable income of exactly $1,596 (1.2 × 15,960 / 12) gets $1 under the statute + and $0 under the rule. + pe_us: + follows: statute + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/8017 + state: ruled + note: 'Code not yet on main: ia_ssa.' - id: us-id:grocery-credit-claimable-spouse program: income-tax years: From 24231f8cb003dbc4b46020dc2ea3121a8b3d3b75 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 21 Oct 2026 15:25:57 -0400 Subject: [PATCH 29/33] Keep SGA workers in Iowa's SMME disability test Iowa Code 249.3(4)(a)(2), 441 IAC 51.7(2) and 6-B p.10 say substantial gainful activity does not preclude SMME disability, so the SMME branch reads meets_ssi_disability_criteria. SSI counts no income for a person it does not treat as aged, blind or disabled, so SMME income applies SSI's exclusions to that person's own income (Case 77). Also name SMME correctly in the candidate entry and correct Case 65's comment. Co-Authored-By: Claude Opus 5.5 --- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 33 +++++++++++++++++-- .../hhs/ssa/ia_ssa_nonfinancial_eligible.py | 13 ++++---- .../hhs/ssa/ia_ssa_smme_countable_income.py | 22 ++++++++++++- source_conflicts/candidates.yaml | 4 +-- 4 files changed, 61 insertions(+), 11 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 cab0916a067..7ad41534297 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 @@ -1879,8 +1879,9 @@ 2026: IA output: # The child is the parent's tax dependent, so SSI's spouse test does not - # pair them and the parent gets the individual allowance. The child is - # not under 18, so there is no dependent-child allowance. + # pair them and the parent gets the individual allowance. SSI's child + # test reaches students only while under 22, so there is no + # dependent-child allowance. # SSI 994 - (800 - 20) = 214; care income 800 + 214 = 1,014; # participation 1,014 - 994 = 20; 400 - 20 = 380. ia_ssa_has_spouse: [false, false] @@ -2226,3 +2227,31 @@ ia_ssa_federal: 0 ia_ssa_smme_countable_income: 2_000 ia_ssa: 1 + +- name: Case 77, a disabled SMME applicant working above the SGA level still qualifies. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + # Reviewer example: SSDI of $900 and wages of $2,000 a month, above the + # 2026 SGA level of $1,690. + social_security_disability: + 2026: 10_800 + employment_income: + 2026: 24_000 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + output: + # SGA bars SSI disability, but Iowa Code 249.3(4)(a)(2) says it "shall not + # preclude a determination of disability" for SMME. SMME income + # (900 - 20) + (2,000 - 65) / 2 = 1,847.50 is at least 1,596. + ssi_engaged_in_sga: true + is_ssi_disabled: false + ssi: 0 + ia_ssa_smme_countable_income: 1_847.5 + ia_ssa: 1 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py index 6b4909e4f23..6f605e0025f 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_nonfinancial_eligible.py @@ -27,11 +27,12 @@ def formula(person, period, parameters): pursues_ssi = person("takes_up_ssi_if_eligible", period.this_year) | ( person("uncapped_ssi", period) <= 0 ) - # NOTE: The SMME exception for a disabled person engaged in substantial - # gainful activity (Iowa Code 249.3(4)(a)(2); 441 IAC 51.7(2); 6-B p.10: - # "an applicant must meet disability standards other than the inability - # to engage in substantial gainful activity") is not modeled, because - # is_ssi_disabled excludes people working above the SGA level. + # SMME disability excludes the substantial gainful activity screen: + # Iowa Code 249.3(4)(a)(2) says SGA "shall not preclude a determination + # of disability", 441 IAC 51.7(2) excepts "limits on substantial gainful + # activity", and 6-B p.10 requires "disability standards other than the + # inability to engage in substantial gainful activity". So SMME reads + # meets_ssi_disability_criteria rather than is_ssi_disabled (Case 77). # NOTE: Iowa Code 249.3(4)(a) limits the SMME supplement to a person # "Sixty-five years of age or older" or "Disabled as defined by 42 # U.S.C. §1382c(a)(3)". 441 IAC 51.7(2) requires "all eligibility @@ -44,7 +45,7 @@ def formula(person, period, parameters): # is disabled does (ia_ssa.yaml Cases 72 and 76). aged_blind_disabled = person("is_ssi_aged_blind_disabled", period.this_year) aged_or_disabled = person("is_ssi_aged", period.this_year) | person( - "is_ssi_disabled", period.this_year + "meets_ssi_disability_criteria", period.this_year ) smme = category == category.possible_values.SMME return ( diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py index 78b1f1075ee..30701784bbf 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py @@ -1,4 +1,7 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.ssa.ssi.eligibility.income._apply_ssi_exclusions import ( + _apply_ssi_exclusions, +) class ia_ssa_smme_countable_income(Variable): @@ -8,7 +11,7 @@ class ia_ssa_smme_countable_income(Variable): definition_period = MONTH unit = USD defined_for = StateCode.IA - documentation = "SSI countable income plus any SSI payment, combined for a couple whose SSI couple computation applies. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." + documentation = "SSI countable income plus any SSI payment, combined for a couple whose SSI couple computation applies. For a disabled person working above the SGA level, whom SSI does not count, the person's own income after SSI's exclusions. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." reference = ( # Iowa Code 249.3(4)(g) "https://www.legis.iowa.gov/docs/code/249.pdf#page=2", @@ -31,5 +34,22 @@ def formula(person, period, parameters): # still for two people. Group-specific Medicaid budgeting is not # modeled. income = person("ssi_countable_income", period) + person("ssi", period) + # SSI counts income only for people it treats as aged, blind or + # disabled, so ssi_countable_income is 0 for a disabled person working + # above the SGA level, whom SMME still covers (Iowa Code + # 249.3(4)(a)(2)). That person's own income gets SSI's exclusions + # instead (ia_ssa.yaml Case 77). + # NOTE: That person's income is not combined with a spouse's, and none + # is deemed from a spouse or parent. + earned = max_(person("ssi_earned_income", period), 0) + unearned = person("ssi_unearned_income", period) + own_income = ( + _apply_ssi_exclusions( + earned * MONTHS_IN_YEAR, unearned * MONTHS_IN_YEAR, parameters, period + ) + / MONTHS_IN_YEAR + ) + counted_by_ssi = person("is_ssi_aged_blind_disabled", period.this_year) + income = where(counted_by_ssi, income, own_income) joint = person("ssi_couple_computation_applies", period) return where(joint, person.marital_unit.sum(income), income) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 5b70dc049e8..8b30414cc7d 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -1781,8 +1781,8 @@ candidates: from: 2026 to: 2026 type: calendar - question: Can a blind person under 65 who is not disabled receive Iowa's supplement for people with medical - expenses (SMME)? + question: Can a blind person under 65 who is not disabled receive Iowa's Supplement for Medicare and Medicaid + Eligibles (SMME)? sources: - kind: statute citation: Iowa Code 249.3(4)(a) From 8cbe544ae7dc20151da4d04700d311a9a3fefed1 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 22 Oct 2026 09:49:52 -0400 Subject: [PATCH 30/33] Address Pavel's round-4 review of Iowa SSA - Size SMME's poverty guideline by whether SMME income includes a spouse's income (couple computation or SSI spousal deeming), per 6-B p.77 and 8-E p.12 (Cases 81-84). - Use the prior year's poverty guideline before April, when Iowa adopts the new one (441 IAC 75.1; Cases 78-80); move the SMME boundary cases to April. - List the residential care per diem statute conflict as a candidate and cite Iowa Code 249.12(3) in the NOTE. - Add the 2025 dependent amount, per diem and personal needs allowance from General Letter 6-B-46 (Case 86), and a test of entry-month resource pooling (Case 85). - Describe the model's child test in Case 65's comment. Co-Authored-By: Claude Opus 5.5 --- .../states/ia/hhs/ssa/dependent_amount.yaml | 3 + .../ia/hhs/ssa/fpg_year_start_month.yaml | 14 + .../states/ia/hhs/ssa/rcf_daily_limit.yaml | 3 + .../states/ia/hhs/ssa/rcf_personal_needs.yaml | 3 + .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 337 +++++++++++++++++- .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 28 +- .../hhs/ssa/ia_ssa_smme_countable_income.py | 19 +- source_conflicts/candidates.yaml | 37 +- 8 files changed, 409 insertions(+), 35 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ia/hhs/ssa/fpg_year_start_month.yaml diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml index 1c32d33aae0..509cd78fdb2 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml @@ -1,5 +1,6 @@ description: Iowa provides this amount as the monthly dependent-person supplement under the State Supplementary Assistance program. values: + 2025-01-01: 503 2026-01-01: 518 metadata: @@ -17,3 +18,5 @@ metadata: href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 - title: SSA POMS SI 01415.058 F.2 (TN 95, 08-26), Iowa payment levels href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f2 + - title: "Iowa HHS General Letter 6-B-46 (effective January 1, 2025) #page 1-2" + href: https://hhs.iowa.gov/media/15607/download#page=1 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/fpg_year_start_month.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/fpg_year_start_month.yaml new file mode 100644 index 00000000000..1d4cf8203f2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/fpg_year_start_month.yaml @@ -0,0 +1,14 @@ +description: Iowa begins applying the current calendar year's federal poverty guidelines to the State Supplementary Assistance SMME income test in this month. +values: + 2026-01-01: 4 + +metadata: + unit: month + period: year + label: Iowa SSA SMME poverty guideline year start month + # Earlier months use the prior year's guidelines. + reference: + - title: 441 IAC 75.1, federal poverty level "revised annually on April 1" + href: https://www.legis.iowa.gov/docs/iac/chapter/441.75.pdf#page=2 + - title: Iowa HHS RC-0130 (Rev. 04/26), 120% of the federal poverty level effective 4/1/26 + href: https://hhs.iowa.gov/media/6948/download#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml index 6d874652e40..d8ce92b7302 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml @@ -1,5 +1,6 @@ description: Iowa limits the residential care facility daily rate to this amount under the State Supplementary Assistance program. values: + 2025-01-01: 37.6 2026-01-01: 38.47 metadata: @@ -18,3 +19,5 @@ metadata: href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 - title: Iowa Code 249.12(3) href: https://www.legis.iowa.gov/docs/code/249.pdf#page=5 + - title: "Iowa HHS General Letter 6-B-46 (effective January 1, 2025) #page 1-2" + href: https://hhs.iowa.gov/media/15607/download#page=1 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml index 8e5aa9f405d..68fab5d031d 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml @@ -1,5 +1,6 @@ description: Iowa provides this amount as the monthly residential care personal needs allowance under the State Supplementary Assistance program. values: + 2025-01-01: 126 2026-01-01: 130 metadata: @@ -26,3 +27,5 @@ metadata: href: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 - title: Iowa Code 249.9A(1) href: https://www.legis.iowa.gov/docs/code/249.pdf#page=4 + - title: "Iowa HHS General Letter 6-B-46 (effective January 1, 2025) #page 1-2" + href: https://hhs.iowa.gov/media/15607/download#page=1 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 7ad41534297..84c14cc8789 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 @@ -947,7 +947,8 @@ ia_ssa_category: SMME ia_ssa_smme_coverage_eligible: true output: - # SMME income 2,000 - 20 = 1,980 exceeds 1.2 * 15,960 / 12 = 1,596. + # SMME income 2,000 - 20 = 1,980 exceeds January's 1.2 * 15,650 / 12 = 1,565 + # (Iowa uses the 2025 guideline until April). ia_ssa_nonfinancial_eligible: true ia_ssa_smme_countable_income: 1_980 ia_ssa: 1 @@ -1029,7 +1030,7 @@ ia_ssa: 328.57 - name: Case 44, SMME income at exactly 120 percent of poverty qualifies under Iowa Code 249.3(4)(g). - period: 2026-01 + period: 2026-04 absolute_error_margin: 0.01 input: state_code: @@ -1040,12 +1041,13 @@ ia_ssa_smme_coverage_eligible: true ia_ssa_smme_countable_income: 1_596 output: - # 1.2 * 15,960 / 12 = 1,596; the statute requires income "of at least" - # 120 percent, so 1,596 qualifies. + # From April, Iowa uses the 2026 guideline (441 IAC 75.1): 1.2 * 15,960 / 12 + # = 1,596; the statute requires income "of at least" 120 percent, so 1,596 + # qualifies. ia_ssa: 1 - name: Case 45, SMME income one cent below 120 percent of poverty. - period: 2026-01 + period: 2026-04 absolute_error_margin: 0.01 input: state_code: @@ -1056,7 +1058,7 @@ ia_ssa_smme_coverage_eligible: true ia_ssa_smme_countable_income: 1_595.99 output: - # 1,595.99 is below 1.2 * 15,960 / 12 = 1,596, so no SMME. + # 1,595.99 is below April's 1.2 * 15,960 / 12 = 1,596, so no SMME. ia_ssa: 0 - name: Case 46, manual example excludes one-third of a child's child support from participation. @@ -1118,10 +1120,10 @@ # Iowa Code 249.3(4)(g): income "of at least one hundred twenty percent of the # federal poverty level" (441 IAC 51.7(6) and 6-B p.77 say "exceed"; the model # follows the statute). Case 47 is an aged couple with Social Security of -# $1,700 a month each; Cases 48-49 bracket the two-person threshold of -# 1.2 * (15,960 + 5,680) / 12 = 2,164. +# $1,700 a month each; Cases 48-49 bracket the two-person threshold from April +# 2026 (441 IAC 75.1), 1.2 * (15,960 + 5,680) / 12 = 2,164. - name: Case 47, an SMME couple's combined income is compared with the two-person guideline. - period: 2026-01 + period: 2026-04 absolute_error_margin: 0.01 input: people: @@ -1167,7 +1169,7 @@ ia_ssa: [1, 1] - name: Case 48, an SMME couple just above the two-person guideline with one spouse covered. - period: 2026-01 + period: 2026-04 absolute_error_margin: 0.01 input: people: @@ -1212,7 +1214,7 @@ ia_ssa: [1, 0] - name: Case 49, an SMME couple just below the two-person guideline. - period: 2026-01 + period: 2026-04 absolute_error_margin: 0.01 input: people: @@ -1879,9 +1881,9 @@ 2026: IA output: # The child is the parent's tax dependent, so SSI's spouse test does not - # pair them and the parent gets the individual allowance. SSI's child - # test reaches students only while under 22, so there is no - # dependent-child allowance. + # pair them and the parent gets the individual allowance. The model's + # SSI child test (is_child) covers only children under 18, so the + # 22-year-old student gets no dependent-child allowance. # SSI 994 - (800 - 20) = 214; care income 800 + 214 = 1,014; # participation 1,014 - 994 = 20; 400 - 20 = 380. ia_ssa_has_spouse: [false, false] @@ -2222,7 +2224,7 @@ ia_ssa_smme_coverage_eligible: true output: # Disabled under 42 U.S.C. 1382c(a)(3), so 249.3(4)(a) is met. SMME income - # 2,020 - 20 = 2,000 exceeds 1.2 * 15,960 / 12 = 1,596. + # 2,020 - 20 = 2,000 exceeds January's 1.2 * 15,650 / 12 = 1,565. ssi: 0 ia_ssa_federal: 0 ia_ssa_smme_countable_income: 2_000 @@ -2249,9 +2251,312 @@ output: # SGA bars SSI disability, but Iowa Code 249.3(4)(a)(2) says it "shall not # preclude a determination of disability" for SMME. SMME income - # (900 - 20) + (2,000 - 65) / 2 = 1,847.50 is at least 1,596. + # (900 - 20) + (2,000 - 65) / 2 = 1,847.50 is at least January's 1,565. ssi_engaged_in_sga: true is_ssi_disabled: false ssi: 0 ia_ssa_smme_countable_income: 1_847.5 ia_ssa: 1 + +# 441 IAC 75.1 revises the federal poverty level "annually on April 1", so +# January-March use the prior year's guideline: 1.2 * 15,650 / 12 = 1,565 for +# one person and 1.2 * (15,650 + 5,500) / 12 = 2,115 for two (RC-0130). +- name: Case 78, in January SMME income at the prior year's 120 percent qualifies. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + ia_ssa_smme_countable_income: 1_565 + output: + ia_ssa: 1 + +- name: Case 79, in January SMME income one cent below the prior year's 120 percent. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + ia_ssa_smme_countable_income: 1_564.99 + output: + ia_ssa: 0 + +- name: Case 80, in January an SMME couple is compared with the prior year's two-person guideline. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + # $1,068 a month each. + social_security_retirement: + 2026: 12_816 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 70 + social_security_retirement: + 2026: 12_816 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 1,068 + 1,068 - 20 = 2,116 > 1,491, so no SSI. 2,116 is at least + # January's 2,115, though below April's 2,164. + ia_ssa_smme_countable_income: [2_116, 2_116] + ia_ssa: [1, 1] + +# 6-B Income (SMME) p.77 follows SSI income criteria, and 8-E p.12 processes an +# applicant "as a one-person household" when SSI deems nothing from a spouse. +# So the two-person guideline applies only when SMME income includes a +# spouse's income. +- name: Case 81, an SMME couple budgeted separately because one spouse is in a medical facility. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + social_security_retirement: + 2026: 20_400 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 70 + social_security_retirement: + 2026: 20_400 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 20 CFR 416.414(b)(3) computes the spouses separately, so each one's + # 1,700 - 20 = 1,680 is compared with the one-person 1,596. + ssi_couple_computation_applies: [false, false] + ia_ssa_smme_countable_income: [1_680, 1_680] + ia_ssa: [1, 1] + +- name: Case 82, an SMME applicant working above the SGA level is compared with the one-person guideline. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + # Case 77's worker: SSDI of $900 and wages of $2,000 a month. + social_security_disability: + 2026: 10_800 + employment_income: + 2026: 24_000 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 45 + # A spouse earning $1,000 a month. + employment_income: + 2026: 12_000 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # SSI doesn't count person1, so SMME income is person1's own 1,847.50, + # with no spouse income, compared with the one-person 1,596. person2's own + # income is (1,000 - 20 - 65) / 2 = 457.50. + ia_ssa_smme_countable_income: [1_847.5, 457.5] + ia_ssa: [1, 0] + +- name: Case 83, SSI deems nothing from a spouse with a 497 dollar pension, so the one-person guideline applies. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + # $1,620 a month. + social_security_retirement: + 2026: 19_440 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 60 + # $497 a month, the SSI couple rate less the individual rate. + pension_income: + 2026: 5_964 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 497 is not more than 1,491 - 994 = 497, so SSI deems nothing and 8-E + # p.12 processes person1 "as a one-person household": 1,620 - 20 = 1,600 is + # at least 1,596. + is_ssi_spousal_deeming_applies: [false, false] + ia_ssa_smme_countable_income: [1_600, 477] + ia_ssa: [1, 0] + +- name: Case 84, SSI deems a spouse's 498 dollar pension, so the two-person guideline applies. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + social_security_retirement: + 2026: 19_440 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 60 + # $498 a month. + pension_income: + 2026: 5_976 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 498 > 497, so SSI deems the spouse's income: 1,620 + 498 - 20 = 2,098, + # below the two-person 2,164. + is_ssi_spousal_deeming_applies: [true, false] + ia_ssa_smme_countable_income: [2_098, 478] + ia_ssa: [0, 0] + +- name: Case 85, a residential care couple pools resources in the month of entry only. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # Case 57's Mr. K, with resources of $2,100. + social_security_retirement: 2_100 + ssi_countable_resources: 2_100 + ia_ssa_category: + 2026-03: RESIDENTIAL_CARE + 2026-04: RESIDENTIAL_CARE + ia_ssa_care_partial_month_days: + 2026-03: 22 + ia_ssa_care_initial_partial_month: + 2026-03: true + person2: + age: 70 + social_security_retirement: 1_200 + marital_units: + couple: + 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: + # 6-B p.60: "treat the spouses as a couple during the month of entry", so + # March tests 2,100 against the $3,000 couple limit (p.12). From April the + # resident is tested alone, and 2,100 is over $2,000. + ia_ssa_rcf_couple_budget: + 2026-03: [true, false] + 2026-04: [false, false] + ia_ssa_eligible: + 2026-03: [true, true] + 2026-04: [false, true] + ia_ssa: + 2026-03: [846.34, 0] + 2026-04: [0, 0] + +- name: Case 86, residential care in January 2025 uses General Letter 6-B-46's levels. + period: 2025-01 + absolute_error_margin: 0.01 + input: + state_code: + 2025: IA + age: + 2025: 65 + ia_ssa_category: RESIDENTIAL_CARE + output: + # 38.47 is the 2026 rate; GL 6-B-46 sets $37.60 a day and a $126 allowance + # for 2025. 37.60 * 31 = 1,165.60; SSI 967, participation 967 - 126 = 841; + # 1,165.60 - 841 = 324.60. + ia_ssa: 324.6 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 1e077b5fb58..4cef57316ed 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 @@ -38,8 +38,11 @@ def formula(person, period, parameters): # cost-related per diem rate "established by the Department # specifically for each facility" of up to $38.47, or "A flat per diem # rate ... $17.86 beginning February 1, 2004". The model follows the - # rule and pays the maximum rate unless a lower facility rate is - # entered (ia_ssa.yaml Cases 14, 15 and 56). + # rule and Iowa Code 249.12(3), under which privately operated + # facilities "shall be reimbursed based on the maximum per diem rates + # established by the general assembly", and pays the maximum rate + # unless a lower facility rate is entered (ia_ssa.yaml Cases 14, 15 + # and 56). entered_rate = max_(person("ia_ssa_rcf_daily_rate", period), 0) rate = where( entered_rate > 0, @@ -98,11 +101,22 @@ def formula(person, period, parameters): / where(joint, max_(recipients, 1), 1) ) # 441 IAC 51.7(6) and 6-B Income (SMME) p.77 set no family size for - # the poverty guideline. The model uses the recipient and any spouse, - # matching ia_ssa_smme_countable_income, which combines an eligible - # couple's income. - size = where(has_spouse, 2, 1) - fpg = parameters(period).gov.hhs.fpg + # the poverty guideline. 6-B p.77 determines income "according to SSI + # income criteria", and 8-E p.12 says to "Process as a one-person + # household" when SSI deems nothing from an ineligible spouse. So the + # guideline is for two people only when SMME income includes a + # spouse's income: an eligible couple's combined income, or income SSI + # deems from a spouse (ia_ssa.yaml Cases 47-49 and 81-84). + spouse_income = joint | person( + "is_ssi_spousal_deeming_applies", period.this_year + ) + size = where(spouse_income, 2, 1) + # 441 IAC 75.1 revises the federal poverty level "annually on April 1", + # so earlier months use the prior year's guidelines (Cases 78-80). + year = period.start.year + if period.start.month < p.fpg_year_start_month: + year = year - 1 + fpg = parameters(f"{year}-01-01").gov.hhs.fpg poverty = ( fpg.first_person.CONTIGUOUS_US + (size - 1) * fpg.additional_person.CONTIGUOUS_US diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py index 30701784bbf..8b0b2bae2d7 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py @@ -24,15 +24,13 @@ def formula(person, period, parameters): # 6-B Income (SMME): income "is determined according to SSI income # criteria". ia_ssa compares it with 120 percent of the poverty # guideline as Iowa Code 249.3(4)(g) sets it ("at least"; see the NOTE - # in ia_ssa). ia_ssa uses the guideline for - # the recipient and any spouse (ia_ssa_has_spouse), so an eligible - # couple's combined income is compared with the two-person guideline - # (ia_ssa.yaml Cases 47-49). - # NOTE: With an ineligible spouse, SSI countable income includes only - # the income SSI deems from that spouse, and none when the spouse's - # income is at or below the deeming threshold, while the guideline is - # still for two people. Group-specific Medicaid budgeting is not - # modeled. + # in ia_ssa). An eligible couple's combined income is compared with the + # two-person guideline (ia_ssa.yaml Cases 47-49). With an ineligible + # spouse, SSI countable income includes the income SSI deems from that + # spouse, and ia_ssa then uses the two-person guideline; when SSI deems + # nothing, 8-E p.12 says to "Process as a one-person household" + # (Cases 83-84). + # NOTE: Group-specific Medicaid budgeting is not modeled. income = person("ssi_countable_income", period) + person("ssi", period) # SSI counts income only for people it treats as aged, blind or # disabled, so ssi_countable_income is 0 for a disabled person working @@ -40,7 +38,8 @@ def formula(person, period, parameters): # 249.3(4)(a)(2)). That person's own income gets SSI's exclusions # instead (ia_ssa.yaml Case 77). # NOTE: That person's income is not combined with a spouse's, and none - # is deemed from a spouse or parent. + # is deemed from a spouse or parent, so ia_ssa uses the one-person + # guideline (Case 82). earned = max_(person("ssi_earned_income", period), 0) unearned = person("ssi_unearned_income", period) own_income = ( diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 8b30414cc7d..3c0fce99dac 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -1775,6 +1775,39 @@ candidates: state: ruled note: 'Ruled statute-first in October 2026; the rule requires replacing the approximation using claimant inputs, with annual verification because the supplied statutory URL is for 2026. Code not yet on main: ia_is_tax_exempt.' +- id: us-ia:rcf-maximum-per-diem-rate + program: ssi-state-supplement + years: + from: 2026 + to: 2026 + type: calendar + question: Is Iowa's residential care supplement based on the maximum per diem rate, or on the manual's choice of + a facility rate or the $17.86 flat rate? + sources: + - kind: statute + citation: Iowa Code 249.12(3) + url: https://www.legis.iowa.gov/docs/code/249.pdf#page=5 + - kind: regulation + citation: 441 IAC 52.1(3) + url: https://www.legis.iowa.gov/docs/iac/chapter/441.52.pdf#page=1 + - kind: manual + citation: Iowa HHS Employees' Manual 6-B, Billing and Payments (RCF) + url: https://hhs.iowa.gov/media/3987/download?inline=#page=72 + readings: + statute: Privately operated facilities "shall be reimbursed based on the maximum per diem rates established by + the general assembly". + other: The manual gives "two options", a cost-related rate up to $38.47 or "A flat per diem rate ... $17.86 + beginning February 1, 2004". + example: An SSI-only resident with no facility rate entered gets $328.57 in January 2026 at the maximum rate, and + $0 at the flat rate (31 × 17.86 = 553.66, below the $864 participation). + pe_us: + follows: statute + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/8017 + state: ruled + note: 'Code not yet on main: ia_ssa, ia_ssa_rcf_daily_rate. Iowa Code 249.12(3) names privately operated + facilities.' - id: us-ia:smme-blind-under-65 program: ssi-state-supplement years: @@ -1828,8 +1861,8 @@ candidates: readings: statute: Income "of at least one hundred twenty percent of the federal poverty level" qualifies. other: Income "must exceed 120 percent of the federal poverty level". - example: A single applicant with countable income of exactly $1,596 (1.2 × 15,960 / 12) gets $1 under the statute - and $0 under the rule. + example: From April 2026, a single applicant with countable income of exactly $1,596 (1.2 × 15,960 / 12) gets $1 + under the statute and $0 under the rule. pe_us: follows: statute code: [] From 647fdf4ee23956bcc3b65e03554624c61c970144 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 22 Oct 2026 12:01:06 -0400 Subject: [PATCH 31/33] Apply SSI's student exclusion and in-kind support on the SMME SGA path A disabled SMME applicant working above the SGA level is budgeted on own income. That income now subtracts SSI's student earned income exclusion (20 CFR 416.1112(c)(3)) and adds in-kind support and maintenance (416.1130, 416.1140), as ssi_countable_income does (Cases 87-88). Co-Authored-By: Claude Opus 5.5 --- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 53 +++++++++++++++++++ .../hhs/ssa/ia_ssa_smme_countable_income.py | 19 +++++-- 2 files changed, 67 insertions(+), 5 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 84c14cc8789..c41425141f2 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 @@ -2560,3 +2560,56 @@ # for 2025. 37.60 * 31 = 1,165.60; SSI 967, participation 967 - 126 = 841; # 1,165.60 - 841 = 324.60. ia_ssa: 324.6 + +- name: Case 87, an SMME student working above the SGA level keeps SSI's student earned income exclusion. + period: 2026-04 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 20 + is_full_time_student: + 2026: true + meets_ssi_disability_criteria: + 2026: true + # Reviewer example: SSDI of $900 and wages of $2,000 a month. + social_security_disability: + 2026: 10_800 + employment_income: + 2026: 24_000 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + output: + # 20 CFR 416.1112(c)(3): min(min(2,410, 2,000) * 12, 9,730) = 9,730 a + # year, or 810.83 a month. SMME income 880 + (2,000 - 810.83 - 65) / 2 = + # 1,442.08 is below 1,596. + ia_ssa_smme_countable_income: 1_442.08 + ia_ssa: 0 + +- name: Case 88, an SMME worker above the SGA level counts outside shelter support. + period: 2026-04 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 40 + meets_ssi_disability_criteria: + 2026: true + # Reviewer example: SSDI of $500 and wages of $1,700 a month, with + # shelter paid by someone outside the household. + social_security_disability: + 2026: 6_000 + employment_income: + 2026: 20_400 + ssi_receives_outside_shelter_support: + 2026: true + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + output: + # 416.1130 and 416.1140: the presumed maximum value 994 / 3 + 20 = 351.33 + # counts as unearned income. (851.33 - 20) + (1,700 - 65) / 2 = 1,648.83 + # is at least 1,596. + ia_ssa_smme_countable_income: 1_648.83 + ia_ssa: 1 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py index 8b0b2bae2d7..5f678f8e880 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py @@ -11,7 +11,7 @@ class ia_ssa_smme_countable_income(Variable): definition_period = MONTH unit = USD defined_for = StateCode.IA - documentation = "SSI countable income plus any SSI payment, combined for a couple whose SSI couple computation applies. For a disabled person working above the SGA level, whom SSI does not count, the person's own income after SSI's exclusions. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." + documentation = "SSI countable income plus any SSI payment, combined for a couple whose SSI couple computation applies. For a disabled person working above the SGA level, whom SSI does not count, the person's own income, including in-kind support and maintenance, after SSI's exclusions, including the student earned income exclusion. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." reference = ( # Iowa Code 249.3(4)(g) "https://www.legis.iowa.gov/docs/code/249.pdf#page=2", @@ -35,13 +35,22 @@ def formula(person, period, parameters): # SSI counts income only for people it treats as aged, blind or # disabled, so ssi_countable_income is 0 for a disabled person working # above the SGA level, whom SMME still covers (Iowa Code - # 249.3(4)(a)(2)). That person's own income gets SSI's exclusions - # instead (ia_ssa.yaml Case 77). + # 249.3(4)(a)(2)). That person's own income gets SSI's income rules + # instead: the student earned income exclusion (20 CFR + # 416.1112(c)(3)), in-kind support and maintenance (416.1130, 416.1140) + # and the general and earned income exclusions (ia_ssa.yaml Cases 77, + # 87 and 88). # NOTE: That person's income is not combined with a spouse's, and none # is deemed from a spouse or parent, so ia_ssa uses the one-person # guideline (Case 82). - earned = max_(person("ssi_earned_income", period), 0) - unearned = person("ssi_unearned_income", period) + earned = max_( + person("ssi_earned_income", period) + - person("ssi_blind_or_disabled_working_student_exclusion", period), + 0, + ) + unearned = person("ssi_unearned_income", period) + person( + "ssi_in_kind_support_and_maintenance", period + ) own_income = ( _apply_ssi_exclusions( earned * MONTHS_IN_YEAR, unearned * MONTHS_IN_YEAR, parameters, period From 1738284df5c24d6dca53b368c280f55bb36c56c7 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 22 Oct 2026 17:44:26 -0400 Subject: [PATCH 32/33] Address Pavel's round-5 review of Iowa SSA - Deem a spouse's income to an SMME applicant working above the SGA level as 8-E pp.12-13 do, and use the two-person guideline when it is deemed (ia_ssa_smme_spousal_deeming_applies; Case 82 updated, Cases 90-92). - Pin the April guideline switch with a March case (Case 89). - Reword the fpg_year_start_month description to the parameter template. - Add the 2023 and 2024 dependent amount, per diem and personal needs allowance (General Letter 6-B-45 and the 2023 standards; Case 93), and correct the rounding NOTE. Co-Authored-By: Claude Opus 5.5 --- .../states/ia/hhs/ssa/dependent_amount.yaml | 6 + .../ia/hhs/ssa/fpg_year_start_month.yaml | 2 +- .../states/ia/hhs/ssa/rcf_daily_limit.yaml | 6 + .../states/ia/hhs/ssa/rcf_personal_needs.yaml | 12 +- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 168 +++++++++++++++++- .../states/ia/hhs/ssa/_smme_spouse_income.py | 15 ++ .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 12 +- .../hhs/ssa/ia_ssa_smme_countable_income.py | 18 +- .../ia_ssa_smme_spousal_deeming_applies.py | 38 ++++ 9 files changed, 260 insertions(+), 17 deletions(-) create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/_smme_spouse_income.py create mode 100644 policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_spousal_deeming_applies.py diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml index 509cd78fdb2..f4fcd3e0aea 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/dependent_amount.yaml @@ -1,5 +1,7 @@ description: Iowa provides this amount as the monthly dependent-person supplement under the State Supplementary Assistance program. values: + 2023-01-01: 474 + 2024-01-01: 490 2025-01-01: 503 2026-01-01: 518 @@ -20,3 +22,7 @@ metadata: href: https://secure.ssa.gov/poms.nsf/lnx/0501415058#f2 - title: "Iowa HHS General Letter 6-B-46 (effective January 1, 2025) #page 1-2" href: https://hhs.iowa.gov/media/15607/download#page=1 + - title: Iowa HHS General Letter 6-B-45 (effective January 1, 2024) + href: https://hhs.iowa.gov/media/12206/download#page=1 + - title: Iowa HHS 2023 State Supplementary Assistance standards + href: https://hhs.iowa.gov/media/9237/download diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/fpg_year_start_month.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/fpg_year_start_month.yaml index 1d4cf8203f2..72e8753a701 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/fpg_year_start_month.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/fpg_year_start_month.yaml @@ -1,4 +1,4 @@ -description: Iowa begins applying the current calendar year's federal poverty guidelines to the State Supplementary Assistance SMME income test in this month. +description: Iowa uses the current calendar year's federal poverty guidelines from this month for the Supplement for Medicare and Medicaid Eligibles income test under the State Supplementary Assistance program. values: 2026-01-01: 4 diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml index d8ce92b7302..cf9ddf7e825 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_daily_limit.yaml @@ -1,5 +1,7 @@ description: Iowa limits the residential care facility daily rate to this amount under the State Supplementary Assistance program. values: + 2023-01-01: 35.89 + 2024-01-01: 36.82 2025-01-01: 37.6 2026-01-01: 38.47 @@ -21,3 +23,7 @@ metadata: href: https://www.legis.iowa.gov/docs/code/249.pdf#page=5 - title: "Iowa HHS General Letter 6-B-46 (effective January 1, 2025) #page 1-2" href: https://hhs.iowa.gov/media/15607/download#page=1 + - title: "Iowa HHS General Letter 6-B-45 (effective January 1, 2024) #page 1,24" + href: https://hhs.iowa.gov/media/12206/download#page=1 + - title: Iowa HHS 2023 State Supplementary Assistance standards + href: https://hhs.iowa.gov/media/9237/download diff --git a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml index 68fab5d031d..4dd1d24e97d 100644 --- a/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml +++ b/policyengine_us/parameters/gov/states/ia/hhs/ssa/rcf_personal_needs.yaml @@ -1,5 +1,7 @@ description: Iowa provides this amount as the monthly residential care personal needs allowance under the State Supplementary Assistance program. values: + 2023-01-01: 120 + 2024-01-01: 123 2025-01-01: 126 2026-01-01: 130 @@ -13,8 +15,10 @@ metadata: # federal social security benefits are increased due to a recognized increase # in the cost of living". Rounding to the nearest dollar is inferred from # General Letters 6-B-45, 6-B-46 and 6-B-47 ($123, $126 and $130 for - # 2024-2026: 123 * 1.025 = 126.08 and 126 * 1.028 = 129.53). The published - # allowance replaces the projection. + # 2024-2026: 123 * 1.025 = 126.08 and 126 * 1.028 = 129.53). It does not fit + # 2024, when Iowa published $123 although 120 * 1.032 = 123.84, so it only + # approximates projected years. The published allowance replaces the + # projection. uprating: parameter: gov.ssa.uprating rounding: @@ -29,3 +33,7 @@ metadata: href: https://www.legis.iowa.gov/docs/code/249.pdf#page=4 - title: "Iowa HHS General Letter 6-B-46 (effective January 1, 2025) #page 1-2" href: https://hhs.iowa.gov/media/15607/download#page=1 + - title: Iowa HHS General Letter 6-B-45 (effective January 1, 2024) + href: https://hhs.iowa.gov/media/12206/download#page=1 + - title: Iowa HHS 2023 State Supplementary Assistance standards + href: https://hhs.iowa.gov/media/9237/download 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 c41425141f2..a2cda26333a 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 @@ -2375,7 +2375,7 @@ ia_ssa_smme_countable_income: [1_680, 1_680] ia_ssa: [1, 1] -- name: Case 82, an SMME applicant working above the SGA level is compared with the one-person guideline. +- name: Case 82, a spouse's wages are deemed to an SMME applicant working above the SGA level. period: 2026-04 absolute_error_margin: 0.01 input: @@ -2413,10 +2413,11 @@ state_code: 2026: IA output: - # SSI doesn't count person1, so SMME income is person1's own 1,847.50, - # with no spouse income, compared with the one-person 1,596. person2's own - # income is (1,000 - 20 - 65) / 2 = 457.50. - ia_ssa_smme_countable_income: [1_847.5, 457.5] + # 8-E pp.12-13: the spouse's 1,000 is more than 1,491 - 994 = 497, so it + # is deemed: (900 - 20) + (2,000 + 1,000 - 65) / 2 = 2,347.50, at least the + # two-person 2,164. person2's own income is (1,000 - 20 - 65) / 2 = 457.50. + ia_ssa_smme_spousal_deeming_applies: [true, false] + ia_ssa_smme_countable_income: [2_347.5, 457.5] ia_ssa: [1, 0] - name: Case 83, SSI deems nothing from a spouse with a 497 dollar pension, so the one-person guideline applies. @@ -2613,3 +2614,160 @@ # is at least 1,596. ia_ssa_smme_countable_income: 1_648.83 ia_ssa: 1 + +- name: Case 89, in March SMME income at the prior year's 120 percent still qualifies. + period: 2026-03 + absolute_error_margin: 0.01 + input: + state_code: + 2026: IA + age: + 2026: 65 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + ia_ssa_smme_countable_income: 1_565 + output: + # 1.2 * 15,650 / 12 = 1,565 until April (441 IAC 75.1; RC-0130 Rev. 04/25). + ia_ssa: 1 + +- name: Case 90, a spouse's wages deemed to an SMME applicant working above the SGA level reach the two-person guideline. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + # Wages of $1,700 a month, above the $1,690 SGA level. + employment_income: + 2026: 20_400 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 45 + # Wages of $3,000 a month. + employment_income: + 2026: 36_000 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 8-E pp.12-13 deem the spouse's 3,000: (1,700 + 3,000 - 20 - 65) / 2 = + # 2,307.50, at least the two-person 2,164. person2's own income is + # (3,000 - 20 - 65) / 2 = 1,457.50. + ia_ssa_smme_countable_income: [2_307.5, 1_457.5] + ia_ssa: [1, 0] + +- name: Case 91, a spouse's wages deemed to an SMME applicant working above the SGA level leave income below the two-person guideline. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + # Wages of $3,277 a month. + employment_income: + 2026: 39_324 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 45 + # Wages of $600 a month. + employment_income: + 2026: 7_200 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # The spouse's 600 is more than 497, so it is deemed: (3,277 + 600 - 20 - + # 65) / 2 = 1,896, below the two-person 2,164 (own income alone, 1,596, + # would qualify). person2's own income is (600 - 85) / 2 = 257.50. + ia_ssa_smme_countable_income: [1_896, 257.5] + ia_ssa: [0, 0] + +- name: Case 92, nothing is deemed from a spouse with a 497 dollar pension to an SMME applicant working above the SGA level. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + # Case 77's worker: SSDI of $900 and wages of $2,000 a month. + social_security_disability: + 2026: 10_800 + employment_income: + 2026: 24_000 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 45 + # A pension of $497 a month and no wages. + pension_income: + 2026: 5_964 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 497 is not more than 1,491 - 994 = 497, so nothing is deemed and the + # one-person 1,596 applies to 1,847.50. person2's own income is 497 - 20 = 477. + ia_ssa_smme_spousal_deeming_applies: [false, false] + ia_ssa_smme_countable_income: [1_847.5, 477] + ia_ssa: [1, 0] + +- name: Case 93, residential care in January 2024 uses General Letter 6-B-45's levels. + period: 2024-01 + absolute_error_margin: 0.01 + input: + state_code: + 2024: IA + age: + 2024: 70 + ia_ssa_category: RESIDENTIAL_CARE + output: + # GL 6-B-45 sets $36.82 a day and a $123 allowance for 2024. 36.82 * 31 = + # 1,141.42; SSI 943, participation 943 - 123 = 820; 1,141.42 - 820 = 321.42. + ia_ssa: 321.42 diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/_smme_spouse_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/_smme_spouse_income.py new file mode 100644 index 00000000000..2228cdfef7d --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/_smme_spouse_income.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +def smme_spouse_income(person, period): + """A spouse's SSI earned and unearned income after allocations for + ineligible children, which 20 CFR 416.1163(b) deduct from unearned income + first.""" + earned = person("ssi_earned_income", period) + unearned = person("ssi_unearned_income", period) + spouse_earned = person.marital_unit.sum(earned) - earned + spouse_unearned = person.marital_unit.sum(unearned) - unearned + allocations = add(person.tax_unit, period, ["ssi_ineligible_child_allocation"]) + unearned_left = max_(spouse_unearned - allocations, 0) + earned_left = max_(spouse_earned - max_(allocations - spouse_unearned, 0), 0) + return earned_left, unearned_left 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 4cef57316ed..14c499afb8f 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 @@ -105,10 +105,14 @@ def formula(person, period, parameters): # income criteria", and 8-E p.12 says to "Process as a one-person # household" when SSI deems nothing from an ineligible spouse. So the # guideline is for two people only when SMME income includes a - # spouse's income: an eligible couple's combined income, or income SSI - # deems from a spouse (ia_ssa.yaml Cases 47-49 and 81-84). - spouse_income = joint | person( - "is_ssi_spousal_deeming_applies", period.this_year + # spouse's income: an eligible couple's combined income, or income + # deemed from a spouse, by SSI or, for an applicant working above the + # SGA level, by ia_ssa_smme_spousal_deeming_applies (ia_ssa.yaml Cases + # 47-49, 81-84 and 90-92). + spouse_income = ( + joint + | person("is_ssi_spousal_deeming_applies", period.this_year) + | person("ia_ssa_smme_spousal_deeming_applies", period) ) size = where(spouse_income, 2, 1) # 441 IAC 75.1 revises the federal poverty level "annually on April 1", diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py index 5f678f8e880..400f84315fd 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py @@ -1,4 +1,7 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.ia.hhs.ssa._smme_spouse_income import ( + smme_spouse_income, +) from policyengine_us.variables.gov.ssa.ssi.eligibility.income._apply_ssi_exclusions import ( _apply_ssi_exclusions, ) @@ -11,7 +14,7 @@ class ia_ssa_smme_countable_income(Variable): definition_period = MONTH unit = USD defined_for = StateCode.IA - documentation = "SSI countable income plus any SSI payment, combined for a couple whose SSI couple computation applies. For a disabled person working above the SGA level, whom SSI does not count, the person's own income, including in-kind support and maintenance, after SSI's exclusions, including the student earned income exclusion. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." + documentation = "SSI countable income plus any SSI payment, combined for a couple whose SSI couple computation applies. For a disabled person working above the SGA level, whom SSI does not count, the person's own income, including in-kind support and maintenance and any spouse income deemed under SSI's rules, after SSI's exclusions, including the student earned income exclusion. Deductions and financial groups of a Medicaid coverage category that differ from SSI are not modeled." reference = ( # Iowa Code 249.3(4)(g) "https://www.legis.iowa.gov/docs/code/249.pdf#page=2", @@ -39,10 +42,11 @@ def formula(person, period, parameters): # instead: the student earned income exclusion (20 CFR # 416.1112(c)(3)), in-kind support and maintenance (416.1130, 416.1140) # and the general and earned income exclusions (ia_ssa.yaml Cases 77, - # 87 and 88). - # NOTE: That person's income is not combined with a spouse's, and none - # is deemed from a spouse or parent, so ia_ssa uses the one-person - # guideline (Case 82). + # 87 and 88). As 8-E pp.12-13 do, a spouse's income above the couple + # rate less the individual rate is added before the exclusions + # (ia_ssa_smme_spousal_deeming_applies), and ia_ssa then uses the + # two-person guideline (Cases 82 and 90-92). + # NOTE: Income deemed from a parent is not modeled on this path. earned = max_( person("ssi_earned_income", period) - person("ssi_blind_or_disabled_working_student_exclusion", period), @@ -51,6 +55,10 @@ def formula(person, period, parameters): unearned = person("ssi_unearned_income", period) + person( "ssi_in_kind_support_and_maintenance", period ) + deemed = person("ia_ssa_smme_spousal_deeming_applies", period) + spouse_earned, spouse_unearned = smme_spouse_income(person, period) + earned = earned + deemed * spouse_earned + unearned = unearned + deemed * spouse_unearned own_income = ( _apply_ssi_exclusions( earned * MONTHS_IN_YEAR, unearned * MONTHS_IN_YEAR, parameters, period diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_spousal_deeming_applies.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_spousal_deeming_applies.py new file mode 100644 index 00000000000..f0f2d7e8ab8 --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_spousal_deeming_applies.py @@ -0,0 +1,38 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.ia.hhs.ssa._smme_spouse_income import ( + smme_spouse_income, +) + + +class ia_ssa_smme_spousal_deeming_applies(Variable): + value_type = bool + entity = Person + label = "Iowa SMME deems spouse income to an applicant working above the SGA level" + definition_period = MONTH + defined_for = StateCode.IA + reference = ( + "https://www.law.cornell.edu/cfr/text/20/416.1163", + # 8-E PDF pages 11-13 + "https://hhs.iowa.gov/media/4011/download?inline#page=11", + ) + + def formula(person, period, parameters): + # 6-B Income (SMME) p.77 determines income "according to SSI income + # criteria", and 8-E pp.11-13 deem an ineligible spouse's income for + # State Supplementary Assistance groups other than the Medically + # Needy, in-home care, dependent person and MEPD groups. SSI's deeming + # variables apply only to people SSI treats as aged, blind or + # disabled, so this test covers a disabled applicant working above the + # SGA level (Iowa Code 249.3(4)(a)(2), (c)): a spouse's income after + # child allocations is deemed when it is more than the couple rate + # less the individual rate. + applicant = person("meets_ssi_disability_criteria", period.this_year) & ~person( + "is_ssi_aged_blind_disabled", period.this_year + ) + earned, unearned = smme_spouse_income(person, period) + p = parameters(period).gov.ssa.ssi.amount + return ( + applicant + & person("ia_ssa_has_spouse", period) + & (earned + unearned > p.couple - p.individual) + ) From 99f005d419977fd99aff3eb035dd3f8c7f78d448 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 23 Oct 2026 19:21:47 -0400 Subject: [PATCH 33/33] Address Pavel's round-6 review of Iowa SSA - Deem nothing on the SMME SGA path from a spouse in a medical treatment facility, who is not a household member (20 CFR 416.1167; 8-E p.11; Case 96). - Treat a spouse SSI counts as aged, blind or disabled as an eligible spouse, combining the couple's income with no $497 test or child allocations (8-E p.12; 8-F pp.73-74; Case 97). - Pin the child-allocation order and a deemed spouse pension at $497.01 (Cases 94-95). Co-Authored-By: Claude Opus 5.5 --- .../gov/states/ia/hhs/ssa/ia_ssa.yaml | 185 ++++++++++++++++++ .../states/ia/hhs/ssa/_smme_spouse_income.py | 20 +- .../variables/gov/states/ia/hhs/ssa/ia_ssa.py | 6 +- .../hhs/ssa/ia_ssa_smme_countable_income.py | 5 +- .../ia_ssa_smme_spousal_deeming_applies.py | 30 ++- 5 files changed, 237 insertions(+), 9 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 a2cda26333a..cbd7d789191 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 @@ -2771,3 +2771,188 @@ # GL 6-B-45 sets $36.82 a day and a $123 allowance for 2024. 36.82 * 31 = # 1,141.42; SSI 943, participation 943 - 123 = 820; 1,141.42 - 820 = 321.42. ia_ssa: 321.42 + +- name: Case 94, a child's allocation comes off a spouse's pension first and then wages before deeming to an SMME applicant working above the SGA level. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + # Wages of $1,700 a month, above the $1,690 SGA level. + employment_income: + 2026: 20_400 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 45 + # A pension of $200 and wages of $2,880 a month. + pension_income: + 2026: 2_400 + employment_income: + 2026: 34_560 + person3: + age: + 2026: 10 + marital_units: + couple: + members: [person1, person2] + child: + 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: + 2026: IA + output: + # 8-E steps 1-3: the child's 497 allocation takes the spouse's 200 of + # pension and 297 of wages, leaving 2,880 - 297 = 2,583 > 497 to deem. + # (1,700 + 2,583 - 20 - 65) / 2 = 2,099, below January's two-person 2,115. + # person2's own income is (200 - 20) + (2,880 - 65) / 2 = 1,587.50. + ssi_ineligible_child_allocation: [0, 0, 497] + ia_ssa_smme_spousal_deeming_applies: [true, false, false] + ia_ssa_smme_countable_income: [2_099, 1_587.5, 0] + ia_ssa: [0, 0, 0] + +- name: Case 95, a spouse's 497.01 dollar pension is deemed to an SMME applicant working above the SGA level. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + # Case 77's worker: SSDI of $900 and wages of $2,000 a month. + social_security_disability: + 2026: 10_800 + employment_income: + 2026: 24_000 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 45 + # A pension of $497.01 a month and no wages. + pension_income: + 2026: 5_964.12 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 497.01 is more than 1,491 - 994 = 497, so the pension is deemed as + # unearned income: (900 + 497.01 - 20) + (2,000 - 65) / 2 = 2,344.51, at + # least January's two-person 2,115. person2's own income is 497.01 - 20. + ia_ssa_smme_spousal_deeming_applies: [true, false] + ia_ssa_smme_countable_income: [2_344.51, 477.01] + ia_ssa: [1, 0] + +- name: Case 96, nothing is deemed to an SMME applicant working above the SGA level from a spouse who lives in a medical facility. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + employment_income: + 2026: 39_324 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 70 + pension_income: + 2026: 6_240 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 20 CFR 416.1167(a)(1); 8-E p.11-12 "same household": the spouse's 520 + # pension is not deemed. person1's own income is (3,277 - 20 - 65) / 2 = + # 1,596, at least the one-person 1,596 (with deeming it would be 2,106, + # below the two-person 2,164). person2's 2,106 comes from SSI's federal + # deeming, which does not yet apply 20 CFR 416.1163(f)(5). + ia_ssa_smme_spousal_deeming_applies: [false, false] + ia_ssa_smme_countable_income: [1_596, 2_106] + ia_ssa: [1, 0] + +- name: Case 97, an aged spouse is not an ineligible spouse, so an SMME applicant working above the SGA level is budgeted as a couple. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 50 + meets_ssi_disability_criteria: + 2026: true + employment_income: + 2026: 39_324 + ia_ssa_category: SMME + ia_ssa_smme_coverage_eligible: true + person2: + age: + 2026: 70 + social_security_retirement: + 2026: 4_800 + marital_units: + couple: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: IA + output: + # 8-E p.12: an ineligible spouse is "not eligible for SSI or + # non-MAGI-related Medicaid, or State Supplementary Assistance". The + # spouse is aged, so the couple's income is combined with no $497 test: + # (400 - 20) + (3,277 - 65) / 2 = 1,986 < 2,164. Alone, 1,596 would + # qualify against the one-person 1,596. + ia_ssa_smme_spousal_deeming_applies: [true, false] + ia_ssa_smme_countable_income: [1_986, 1_986] + ia_ssa: [0, 0] diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/_smme_spouse_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/_smme_spouse_income.py index 2228cdfef7d..9711918f05f 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/_smme_spouse_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/_smme_spouse_income.py @@ -1,15 +1,27 @@ from policyengine_us.model_api import * +def smme_spouse_is_aged_blind_disabled(person, period): + """Whether the other member of a two-person marital unit is a person SSI + treats as aged, blind or disabled. For an applicant whom SSI does not + count, any such member of the marital unit is the spouse.""" + abd = person("is_ssi_aged_blind_disabled", period.this_year) + return person.marital_unit.sum(abd) - abd > 0 + + def smme_spouse_income(person, period): - """A spouse's SSI earned and unearned income after allocations for - ineligible children, which 20 CFR 416.1163(b) deduct from unearned income - first.""" + """A spouse's SSI earned and unearned income. For an ineligible spouse, + allocations for ineligible children are deducted, from unearned income + first (20 CFR 416.1163(b)(3)). A spouse whom SSI treats as aged, blind or + disabled is not an ineligible spouse, and the couple's income is combined + as for an eligible couple, with no allocations.""" earned = person("ssi_earned_income", period) unearned = person("ssi_unearned_income", period) spouse_earned = person.marital_unit.sum(earned) - earned spouse_unearned = person.marital_unit.sum(unearned) - unearned - allocations = add(person.tax_unit, period, ["ssi_ineligible_child_allocation"]) + allocations = add( + person.tax_unit, period, ["ssi_ineligible_child_allocation"] + ) * ~smme_spouse_is_aged_blind_disabled(person, period) unearned_left = max_(spouse_unearned - allocations, 0) earned_left = max_(spouse_earned - max_(allocations - spouse_unearned, 0), 0) return earned_left, unearned_left 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 14c499afb8f..9b7013e52cd 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 @@ -107,8 +107,10 @@ def formula(person, period, parameters): # guideline is for two people only when SMME income includes a # spouse's income: an eligible couple's combined income, or income # deemed from a spouse, by SSI or, for an applicant working above the - # SGA level, by ia_ssa_smme_spousal_deeming_applies (ia_ssa.yaml Cases - # 47-49, 81-84 and 90-92). + # SGA level, by ia_ssa_smme_spousal_deeming_applies (a spouse's income + # above the couple rate less the individual rate, or an aged, blind or + # disabled spouse's income; ia_ssa.yaml Cases 47-49, 81-84, 90-92 and + # 94-97). spouse_income = ( joint | person("is_ssi_spousal_deeming_applies", period.this_year) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py index 400f84315fd..f2c2cab6a28 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_countable_income.py @@ -43,9 +43,10 @@ def formula(person, period, parameters): # 416.1112(c)(3)), in-kind support and maintenance (416.1130, 416.1140) # and the general and earned income exclusions (ia_ssa.yaml Cases 77, # 87 and 88). As 8-E pp.12-13 do, a spouse's income above the couple - # rate less the individual rate is added before the exclusions + # rate less the individual rate, or an aged, blind or disabled + # spouse's income, is added before the exclusions # (ia_ssa_smme_spousal_deeming_applies), and ia_ssa then uses the - # two-person guideline (Cases 82 and 90-92). + # two-person guideline (Cases 82, 90-92 and 94-97). # NOTE: Income deemed from a parent is not modeled on this path. earned = max_( person("ssi_earned_income", period) diff --git a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_spousal_deeming_applies.py b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_spousal_deeming_applies.py index f0f2d7e8ab8..2541f0cb848 100644 --- a/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_spousal_deeming_applies.py +++ b/policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_smme_spousal_deeming_applies.py @@ -1,6 +1,7 @@ from policyengine_us.model_api import * from policyengine_us.variables.gov.states.ia.hhs.ssa._smme_spouse_income import ( smme_spouse_income, + smme_spouse_is_aged_blind_disabled, ) @@ -12,8 +13,11 @@ class ia_ssa_smme_spousal_deeming_applies(Variable): defined_for = StateCode.IA reference = ( "https://www.law.cornell.edu/cfr/text/20/416.1163", + "https://www.ecfr.gov/current/title-20/section-416.1167", # 8-E PDF pages 11-13 "https://hhs.iowa.gov/media/4011/download?inline#page=11", + # 8-F PDF pages 73-74 + "https://hhs.iowa.gov/media/4012/download?inline#page=73", ) def formula(person, period, parameters): @@ -29,10 +33,34 @@ def formula(person, period, parameters): applicant = person("meets_ssi_disability_criteria", period.this_year) & ~person( "is_ssi_aged_blind_disabled", period.this_year ) + # 8-E p.11 deems only while the applicant lives "in the same + # household" with the spouse. Under 20 CFR 416.1167(a)(1) an absence + # is temporary only if the person returns in the same or the next + # month, so a spouse (or the applicant) in a medical treatment + # facility for the month is not a household member and nothing is + # deemed (ia_ssa.yaml Case 96). + # NOTE: Intent to return is not modeled, as in + # ssi_couple_computation_applies. + apart = person.marital_unit.any( + person("ssi_lives_in_medical_treatment_facility", period) + ) + # 8-E p.12: "An ineligible spouse is a spouse who is not eligible for + # SSI or non-MAGI-related Medicaid, or State Supplementary + # Assistance." Those groups are for aged, blind or disabled people + # (8-F PDF pages 73-74), so, as is_ssi_ineligible_spouse does, a spouse + # SSI treats as aged, blind or disabled is not an ineligible spouse: the + # couple's income is combined with no $497 test, as SSI and + # msp_countable_income combine an eligible couple's income. + # NOTE: 8-E tests eligibility for SSI, non-MAGI-related Medicaid or + # State Supplementary Assistance. The model uses SSI's aged, blind or + # disabled status, so an aged, blind or disabled spouse who qualifies + # for none of them is combined rather than deemed. + eligible_spouse = smme_spouse_is_aged_blind_disabled(person, period) earned, unearned = smme_spouse_income(person, period) p = parameters(period).gov.ssa.ssi.amount return ( applicant & person("ia_ssa_has_spouse", period) - & (earned + unearned > p.couple - p.individual) + & ~apart + & (eligible_spouse | (earned + unearned > p.couple - p.individual)) )