diff --git a/changelog.d/md-ssp.added.md b/changelog.d/md-ssp.added.md new file mode 100644 index 00000000000..34373543d7e --- /dev/null +++ b/changelog.d/md-ssp.added.md @@ -0,0 +1 @@ +Add Maryland Public Assistance to Adults (state SSP). diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index b74241a36b5..b376eeff0df 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -14,6 +14,8 @@ values: - me_ssp # Massachusetts benefits - ma_state_supplement + # Maryland benefits + - md_paa # Michigan benefits - mi_ssp # Colorado benefits @@ -81,6 +83,8 @@ values: - me_ssp # Massachusetts benefits - ma_state_supplement + # Maryland benefits + - md_paa # Michigan benefits - mi_ssp # Colorado benefits diff --git a/policyengine_us/parameters/gov/states/md/dhs/fia/paa/personal_needs_allowance.yaml b/policyengine_us/parameters/gov/states/md/dhs/fia/paa/personal_needs_allowance.yaml new file mode 100644 index 00000000000..f97760640e9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/fia/paa/personal_needs_allowance.yaml @@ -0,0 +1,25 @@ +description: Maryland provides this amount as the personal needs allowance under the Public Assistance to Adults program. + +values: + 2009-01-01: 82 + 2022-01-01: 84 + 2022-07-01: 93 + 2023-07-01: 98 + 2024-07-01: 102 + 2025-07-01: 106 + +metadata: + unit: currency-USD + period: month + label: Maryland PAA personal needs allowance + reference: + - title: COMAR 07.03.07.04(A)(1) Need Requirements + href: https://regs.maryland.gov/us/md/exec/comar/07.03.07.04 + - title: Maryland DHS-FIA Action Transmittal 22-09, FFY22 COLA Mass Mod + href: https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2022/22-09%20AT-%20COLA%20Mass%20Mod%20FFY22.pdf + - title: Maryland DHS-FIA Action Transmittal 22-28, Increase in Personal Needs Allowance + href: https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2022/22-28%20AT%20-%20INCREASE%20IN%20PERSONAL%20NEEDS%20ALLOWANCE.pdf + - title: Maryland DHS-FIA Information Memo 24-05, June 2023 Mass Modification + href: https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2024/24-05%20IM%20-%20JUNE%202023%20MASS%20MODIFICATION.pdf + - title: Maryland DHS-FIA Information Memo 26-04, 2025 PNA Increase + href: https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2026/26-04%20IM%202025%20PNA%20Increase.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/md/dhs/fia/paa/provider_rate.yaml b/policyengine_us/parameters/gov/states/md/dhs/fia/paa/provider_rate.yaml new file mode 100644 index 00000000000..8ca82130603 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/fia/paa/provider_rate.yaml @@ -0,0 +1,44 @@ +description: Maryland provides this amount as the monthly provider rate by living arrangement under the Public Assistance to Adults program. + +metadata: + unit: currency-USD + period: month + label: Maryland PAA provider rate + breakdown: + - md_paa_living_arrangement + reference: + - title: COMAR 07.03.07.04(B)(2), (C)(2), and (D) Need Requirements + href: https://regs.maryland.gov/us/md/exec/comar/07.03.07.04 + - title: COMAR 07.03.07.09A Amount of Grant + href: https://regs.maryland.gov/us/md/exec/comar/07.03.07.09 + - title: Maryland DHS-FIA Action Transmittal 18-11, 2018 COLA Increase + href: https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2018/18-11%20AT%20COLA%20Increase%202018.doc + - title: Maryland DHS-FIA Action Transmittal 23-02, FFY23 COLA Mass Mod (PAA rates remain the same) + href: https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2023/23-02%20AT%20-%20COLA%20Mass%20Mod%20FFY23.pdf#page=3 + +# 2009-01-01 values from COMAR 07.03.07.04(B)(2) (CARE Home Levels A-D) and +# (C)(2) (Licensed Assisted Living). 2018-01-01 values first documented in +# AT 18-11 and unchanged through every subsequent COLA Mass Mod (AT 19-08, +# 20-10, 21-18, 22-09, 23-02 — all say "PAA Rates remain the same"). +# REHAB_RESIDENCE provider_rate is $0 because PAA Manual §900.3 / AT 23-02 +# treat MDH Rehabilitative Residence as PNA-only (the $54/day cost is paid +# directly by MHA, not by PAA). Do not "fix" REHAB to 54 * 30. +CARE_HOME_LEVEL_A: + 2009-01-01: 740 + 2018-01-01: 776 +CARE_HOME_LEVEL_B: + 2009-01-01: 849 + 2018-01-01: 875 +CARE_HOME_LEVEL_C: + 2009-01-01: 1_137 + 2018-01-01: 1_173 +CARE_HOME_LEVEL_D: + 2009-01-01: 1_340 + 2018-01-01: 1_376 +ASSISTED_LIVING: + 2009-01-01: 858 + 2018-01-01: 894 +REHAB_RESIDENCE: + 2009-01-01: 0 +NONE: + 2009-01-01: 0 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 76b5377b5f3..684acd42f3b 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -701,6 +701,12 @@ programs: name: Massachusetts SSP full_name: Massachusetts State Supplementary Payment variable: ma_state_supplement + - state: MD + status: complete + name: Maryland PAA + full_name: Maryland Public Assistance to Adults + variable: md_paa + parameter_prefix: gov.states.md.dhs.fia.paa - state: MI status: complete name: Michigan SSP diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/integration.yaml new file mode 100644 index 00000000000..00452d06534 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/integration.yaml @@ -0,0 +1,558 @@ +# Integration tests for Maryland Public Assistance to Adults (PAA). +# Verifies the prospective SSI cascade method: PAA equals combined need minus +# SSI countable income and imputed federal SSI. Period 2026-01: federal +# individual FBR = $994, couple FBR = $1,491, medical-facility rate = $30, +# PNA = $106. + +- name: Case 1, single SSI in CARE_HOME_LEVEL_B — federal SSI exceeds combined need. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + is_ssi_eligible: [true] + ssi: [994] + md_paa_eligible: [true] + # combined_need = 875 + 106 = 981. imputed SSI = 994. + # PAA = max(981 - 994, 0) = 0. + md_paa_provider_rate: [875] + md_paa_personal_needs_allowance: [106] + md_paa_total_cost_of_care: [981] + md_paa: [0] + +- name: Case 2, SSI recipient with $200/mo earned income in CARE_HOME_LEVEL_C. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + employment_income: 2_400 # $200/mo + md_paa_living_arrangement: CARE_HOME_LEVEL_C + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + # Federal countable = max(0, 200 - 65 - 20) * 0.5 = 57.50. + # SSI = 994 - 57.50 = 936.50. + is_ssi_eligible: [true] + ssi: [936.50] + md_paa_eligible: [true] + # combined_need = 1173 + 106 = 1279. imputed SSI = 936.50. + # countable = 57.50. PAA = 1279 - 936.50 - 57.50 = 285. + md_paa_total_cost_of_care: [1_279] + md_paa: [285] + +- name: Case 3, SSI recipient with $400/mo OASI in ASSISTED_LIVING. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + social_security: 4_800 # $400/mo OASI + employment_income: 0 + md_paa_living_arrangement: ASSISTED_LIVING + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + # Federal countable unearned = 400 - 20 = 380. SSI = 994 - 380 = 614. + is_ssi_eligible: [true] + ssi: [614] + md_paa_eligible: [true] + # combined = 894 + 106 = 1000. imputed SSI = 614. + # countable = 380. PAA = 1000 - 614 - 380 = 6. + md_paa_total_cost_of_care: [1_000] + md_paa: [6] + +- name: Case 4, REHAB_RESIDENCE recipient — state fills gap from $30 medical SSI to PNA. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + employment_income: 0 + md_paa_living_arrangement: REHAB_RESIDENCE + # MDH rehab is a Title XIX medical treatment facility for SSI; + # federal SSI is capped at $30/mo. md_paa_eligible requires both. + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: 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: MD + output: + is_ssi_eligible: [true] + # Federal SSI = $30/mo medical-facility rate (annualized $360). + ssi: [30] + md_paa_eligible: [true] + # combined = 0 + 106 = 106. imputed SSI = $30. + # countable = 0. PAA = 76. + md_paa_provider_rate: [0] + md_paa_personal_needs_allowance: [106] + md_paa: [76] + +- name: Case 5, married couple both SSI-eligible in CARE_HOME_LEVEL_A. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_A + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_A + 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: MD + output: + # Imputed federal SSI uses couple_FBR/2 = $1,491 / 2 = $745.50 per + # spouse. Combined need per person = 776 + 106 = 882, so Maryland fills + # the $136.50 gap for each spouse. + ssi_amount_if_eligible: [745.50, 745.50] + ssi_countable_income: [0, 0] + md_paa_imputed_federal_ssi: [745.50, 745.50] + md_paa_eligible: [true, true] + md_paa: [136.50, 136.50] + +- name: Case 6, person not in PAA facility (NONE) is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + employment_income: 0 + md_paa_living_arrangement: 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: MD + output: + is_ssi_eligible: [true] + ssi: [994] + md_paa_eligible: [false] + md_paa: [0] + +- name: Case 7, applicant with only earned income (no SSA receipt) is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 0 + social_security: 0 + social_security_disability: 0 + employment_income: 36_000 # $3,000/mo + md_paa_living_arrangement: CARE_HOME_LEVEL_B + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + # No federal cash benefit (SSI / SSDI / OASI) → PAA-ineligible per + # COMAR 07.03.07.03(A)(2). + md_paa_eligible: [false] + md_paa: [0] + +- name: Case 8, SSDI recipient with $1,000/mo SSDI in CARE_HOME_LEVEL_C. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi: 0 # Force off; SSDI alone gates eligibility. + ssi_countable_resources: 500 + social_security_disability: 12_000 # $1,000/mo + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: [true] + # combined = 1173 + 106 = 1279. countable = 1000 - 20 = 980. + # Imputed SSI = max(994 - 980, 0) = 14. PAA = 1279 - 980 - 14 = 285. + md_paa: [285] + +- name: Case 9, asymmetric married couple — only one spouse PAA-eligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 9_600 # gates eligibility + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + person2: + age: 60 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + ssi_countable_resources: 0 + employment_income: 0 + md_paa_living_arrangement: NONE + 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: MD + output: + # person2 not in PAA facility → ineligible. person1 eligible via SSI. + # person1 cascade: combined = 1173 + 106 = 1279. ssi_amount_if_eligible + # for an aged spouse paired with a non-ABD spouse falls back to the + # individual FBR ($994). Own SSI receipt is excluded from + # ssi_countable_income by design, so countable = 0 and imputed SSI = + # 994. PAA = 1279 - 994 = 285. Locked intermediates below + # guard against regressions in either assumption. Note: + # ssi_amount_if_eligible returns the maximum federal SSI amount a + # person *would* receive if categorically eligible; it does not gate + # on receipt, so person2 also returns $994. + ssi_amount_if_eligible: [994, 994] + ssi_countable_income: [0, 0] + md_paa_imputed_federal_ssi: [994, 0] + md_paa_eligible: [true, false] + md_paa_provider_rate: [1_173, 0] + md_paa_personal_needs_allowance: [106, 0] + md_paa: [285, 0] + +- name: Case 10, married couple with asymmetric living arrangements (CARE Home A vs C). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_A + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + 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: MD + output: + # Imputed federal SSI uses couple_FBR/2 = $745.50 per spouse. + # Per-person cascade: + # person1 (CARE_HOME_LEVEL_A): combined = 776 + 106 = 882; + # PAA = 882 - 745.50 = 136.50. + # person2 (CARE_HOME_LEVEL_C): combined = 1173 + 106 = 1279; + # PAA = 1279 - 745.50 = 533.50. + # Verifies per-person evaluation produces different PAA amounts within + # one marital unit. + ssi_amount_if_eligible: [745.50, 745.50] + ssi_countable_income: [0, 0] + md_paa_imputed_federal_ssi: [745.50, 745.50] + md_paa_eligible: [true, true] + md_paa: [136.50, 533.50] + +- name: Case 11, OASI recipient who is not aged/blind/disabled is PAA-ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 # Not aged, not blind, not disabled. + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 12_000 # $1,000/mo OASI (e.g., survivor benefits) + social_security_disability: 0 + ssi_countable_resources: 500 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + # COMAR 07.03.07.03(A)(2): OASI receipt qualifies a person ONLY if + # they also meet aged/blind/disabled. A 50-year-old surviving spouse + # is not categorically qualifying, so PAA must reject — exercises + # the `(social_security > 0) & is_categorically_qualifying` branch + # of md_paa_eligible separately from Case 7's no-federal-benefit case. + md_paa_eligible: [false] + md_paa: [0] + +- name: Case 12, aged OASI recipient with $1,000/mo OASI in CARE_HOME_LEVEL_C — positive PAA via OASI pathway. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 # Categorically aged → OASI receipt qualifies for PAA. + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 12_000 # $1,000/mo OASI + social_security_disability: 0 + ssi_countable_resources: 500 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: [true] + # combined = 1173 + 106 = 1279. countable = 1000 - 20 = 980. + # Imputed SSI = max(994 - 980, 0) = 14. PAA = 1279 - 980 - 14 = 285. + md_paa: [285] + +- name: Case 13, married couple both SSI-eligible in CARE_HOME_LEVEL_C — symmetric positive output. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + 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: MD + output: + # Imputed federal SSI uses couple_FBR/2 = $745.50 per spouse. + # combined per spouse = 1173 + 106 = 1279, so PAA = 533.50 each. + # Both spouses receive a positive PAA — verifies the symmetric path. + md_paa_eligible: [true, true] + md_paa_imputed_federal_ssi: [745.50, 745.50] + md_paa: [533.50, 533.50] + +- name: Case 14, pending §300.5 applicant with no income in CARE_HOME_LEVEL_C — positive PAA. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 # Categorically aged. + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + social_security_disability: 0 + ssi_countable_resources: 1_000 + employment_income: 0 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + md_paa_pending_federal_benefit: 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: MD + output: + # Pending pathway gates eligibility; cascade then runs normally. + # combined = 1173 + 106 = 1279. imputed SSI = 994. + # countable = 0. PAA = 285. + md_paa_eligible: [true] + md_paa: [285] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa.yaml new file mode 100644 index 00000000000..6cc5fa1df87 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa.yaml @@ -0,0 +1,191 @@ +# Tests for md_paa main benefit variable. +# Formula (prospective SSI cascade): +# paa = max(combined_need - ssi_countable_income - imputed_federal_ssi, 0) +# REHAB residents impute the $30 federal SSI medical-facility rate. +# 2026 federal SSI individual FBR = $994; PNA = $106. + +- name: Case 1, CARE_HOME_LEVEL_B with only SSI — federal SSI exceeds combined need. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 # gates eligibility + ssi_earned_income: 0 + ssi_unearned_income: 0 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + # combined_need = 875 + 106 = 981. imputed SSI = 994. PAA = 0. + md_paa: 0 + +- name: Case 2, REHAB_RESIDENCE with only SSI receives state-funded gap to PNA. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_earned_income: 0 + ssi_unearned_income: 0 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: REHAB_RESIDENCE + # MDH rehab residents are SSI medical-treatment-facility recipients + # (federal SSI capped at $30/mo). md_paa_eligible requires both flags. + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + households: + household: + members: [person1] + state_code: MD + output: + # combined_need = 0 + 106 = 106. imputed SSI = $30. PAA = 76. + md_paa: 76 + +- name: Case 3, ineligible (NONE living arrangement). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: NONE + households: + household: + members: [person1] + state_code: MD + output: + md_paa: 0 + +- name: Case 4, CARE_HOME_LEVEL_C SSI-only — state fills gap above federal. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_earned_income: 0 + ssi_unearned_income: 0 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + households: + household: + members: [person1] + state_code: MD + output: + # combined_need = 1173 + 106 = 1279. imputed SSI = 994. PAA = 285. + md_paa: 285 + +- name: Case 5, negative earned income does not inflate benefit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 + # Self-employment loss should not reduce countable income below zero. + self_employment_income: -60_000_000 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + households: + household: + members: [person1] + state_code: MD + output: + # ssi_countable_income floors at 0 by design. + # imputed SSI = 994. PAA = 1279 - 994 = 285. + md_paa: 285 + +- name: Case 6, out-of-state recipient is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MA + output: + md_paa: 0 + +- name: Case 7, high-income REHAB recipient — income exhausts federal then state. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 + # $2,500/mo non-SSI unearned * 12 = $30,000/yr. + social_security: 30_000 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: REHAB_RESIDENCE + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + households: + household: + members: [person1] + state_code: MD + output: + # combined = 106. countable = 2500 - 20 = 2480. + # imputed SSI = 0 because countable income exceeds the $30 medical rate. + # PAA = max(106 - 2480, 0) = 0. + md_paa: 0 + +- name: Case 8, CARE_HOME_LEVEL_D recipient gets the largest state supplement. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_D + households: + household: + members: [person1] + state_code: MD + output: + # combined_need = 1376 + 106 = 1482. imputed SSI = 994. PAA = 488. + md_paa: 488 + +# Partial-erosion case: countable income exceeds the imputed medical-facility +# SSI amount but does not fully exhaust the PNA. +- name: Case 9, REHAB recipient with $80/mo unearned — partial state erosion. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 9_600 # gates eligibility + social_security: 960 # $80/mo unearned (in addition to medical SSI) + ssi_countable_resources: 1_000 + md_paa_living_arrangement: REHAB_RESIDENCE + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + households: + household: + members: [person1] + state_code: MD + output: + # countable monthly = 80 - 20 (general exclusion) = 60. + # imputed SSI = max(30 - 60, 0) = 0. + # PAA = max(106 - 60, 0) = 46. Partial reduction (not zero). + md_paa: 46 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_eligible.yaml new file mode 100644 index 00000000000..e07bb4dfb20 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_eligible.yaml @@ -0,0 +1,370 @@ +# Tests for md_paa_eligible variable. +# Eligibility requires: +# - state_code = MD (defined_for filter) +# - ssi > 0 OR social_security_disability > 0 OR (oasi > 0 AND aged/blind/ +# disabled) OR pending §300.5 application (federal cash benefit per +# COMAR 07.03.07.03(A)(2)) +# - ssi_countable_resources <= $2,000 (parity with federal SSI per +# PAA Manual §500) +# - md_paa_living_arrangement != NONE (PAA Manual §300.3, §300.4) +# - REHAB ⇄ ssi_lives_in_medical_treatment_facility consistency + +- name: Case 1, SSI recipient in CARE_HOME_LEVEL_B in Maryland is eligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi: 9_600 # $800/mo SSI as input (YEAR-defined) + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: true + +- name: Case 2, no living arrangement (NONE) is ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: NONE + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +- name: Case 3, no SSI or SSDI receipt is ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi: 0 + social_security_disability: 0 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +- name: Case 4, out-of-state resident is ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MA + output: + md_paa_eligible: false + +# Per COMAR 07.03.07.03(A)(2), applicants who receive SSDI (without SSI) +# on the basis of disability are also PAA-eligible. +- name: Case 5, SSDI-only recipient is eligible. + period: 2025-01 + input: + people: + person1: + age: 60 + ssi: 0 + social_security_disability: 12_000 # $1,000/mo SSDI + ssi_countable_resources: 500 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: true + +# Per PAA Manual §500, the $2,000 SSI resource limit applies. Verify +# the resource gate is enforced independently of SSI receipt. +- name: Case 6, resources above $2,000 limit are ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 3_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +# A person with only earned income (no SSI, SSDI, or OASI receipt) cannot +# qualify for PAA, even if otherwise in a PAA facility — PAA requires +# receipt of a federal cash benefit on the basis of age/blindness/ +# disability per COMAR 07.03.07.03(A)(2). +- name: Case 7, no federal cash benefit receipt is PAA-ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + social_security_disability: 0 + employment_income: 36_000 # $3,000/mo earned income + ssi_countable_resources: 500 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +# Per PAA Manual §300.5 / COMAR 07.03.07.03, applicants in protected living +# arrangements remain eligible while a federal cash benefit application is +# pending or while a no-fault denial is being appealed, provided they meet +# the categorical aged/blind/disabled requirement. +- name: Case 8, pending SSI applicant who is aged is PAA-eligible. + period: 2025-01 + input: + people: + person1: + age: 70 # Categorically aged. + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + social_security_disability: 0 + ssi_countable_resources: 500 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + md_paa_pending_federal_benefit: true + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: true + +- name: Case 9, pending applicant not categorically aged/blind/disabled is ineligible. + period: 2025-01 + input: + people: + person1: + age: 40 # Not aged, not blind, not disabled. + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + social_security_disability: 0 + ssi_countable_resources: 500 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + md_paa_pending_federal_benefit: true + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +# Resource limit boundary: PAA Manual §500 caps at $2,000 (federal SSI +# individual limit). Confirm the boundary applies inclusively at $2,000 +# and excludes $2,001 — guards against off-by-one regressions if the +# parameter or comparison operator ever changes. +- name: Case 10, resources exactly at $2,000 limit are eligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 2_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: true + +- name: Case 11, resources at $2,001 (one dollar over limit) are ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 2_001 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +# §300.5 pending pathway: confirms all three categorical gates (aged, +# blind, disabled) admit a pending applicant. Case 8 covers aged; these +# cover the other two so a regression in one branch isn't masked. +- name: Case 12, pending applicant who is blind is PAA-eligible. + period: 2025-01 + input: + people: + person1: + age: 50 # Not aged. + is_blind: true # Categorically qualifying via blindness. + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + social_security_disability: 0 + ssi_countable_resources: 500 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + md_paa_pending_federal_benefit: true + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: true + +- name: Case 13, pending applicant who is disabled is PAA-eligible. + period: 2025-01 + input: + people: + person1: + age: 50 # Not aged. + is_blind: false + is_disabled: true # Categorically qualifying via disability. + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + social_security_disability: 0 + ssi_countable_resources: 500 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + md_paa_pending_federal_benefit: true + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: true + +# Per COMAR 07.03.07.03(A)(2), OASI receipt qualifies a person ONLY if +# they are also aged/blind/disabled. A 50-year-old surviving spouse +# drawing Social Security survivor benefits is not categorically +# qualifying and must be rejected, even though `social_security > 0`. +- name: Case 14, OASI recipient who is not aged/blind/disabled is ineligible. + period: 2025-01 + input: + people: + person1: + age: 50 # Not aged. + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 12_000 # $1,000/mo OASI (e.g., survivor benefits) + social_security_disability: 0 + ssi_countable_resources: 500 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +# Confirm the $2,000 resource gate still applies on the §300.5 pending +# pathway — eligibility short-circuits regardless of which qualification +# route the applicant uses. +- name: Case 15, pending applicant with resources above $2,000 limit is ineligible. + period: 2025-01 + input: + people: + person1: + age: 70 # Categorically aged. + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + social_security_disability: 0 + ssi_countable_resources: 5_000 # Over the $2,000 SSI limit. + md_paa_living_arrangement: CARE_HOME_LEVEL_B + md_paa_pending_federal_benefit: true + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +# Bidirectional REHAB / SSI medical-facility consistency gate: REHAB +# without the SSI flags set is ineligible (federal SSI would not be +# capped at $30/mo upstream, producing a wrong cascade). +- name: Case 16, REHAB recipient without SSI medical-facility flags is ineligible. + period: 2026-01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: REHAB_RESIDENCE + # ssi_lives_in_medical_treatment_facility intentionally NOT set. + # ssi_medicaid_pays_majority_of_care intentionally NOT set. + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + +# Bidirectional gate (other direction): CARE Home recipient with the +# SSI medical-facility flag accidentally set is ineligible — federal +# SSI would be capped at $30/mo upstream, producing a wrong cascade. +- name: Case 17, CARE Home recipient with SSI medical-facility flag set is ineligible. + period: 2026-01 + input: + people: + person1: + age: 70 + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_imputed_federal_ssi.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_imputed_federal_ssi.yaml new file mode 100644 index 00000000000..9d85205b49d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_imputed_federal_ssi.yaml @@ -0,0 +1,89 @@ +# Tests for md_paa_imputed_federal_ssi. +# Formula: max(uncapped_ssi, 0), gated by Maryland PAA eligibility. + +- name: Case 1, SSI-eligible CARE Home applicant with no income imputes full individual SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + households: + household: + members: [person1] + state_code: MD + output: + ssi_countable_income: 0 + md_paa_imputed_federal_ssi: 994 + +- name: Case 2, OASI income reduces imputed federal SSI dollar-for-dollar after disregard. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi: 0 + social_security: 12_000 + social_security_disability: 0 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + households: + household: + members: [person1] + state_code: MD + output: + # $1,000/mo OASI - $20 general exclusion = $980 countable. + # Imputed federal SSI = max(994 - 980, 0) = 14. + ssi_countable_income: 980 + md_paa_imputed_federal_ssi: 14 + +- name: Case 3, income above the federal SSI amount imputes no federal SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi: 0 + social_security_disability: 30_000 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_C + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: true + md_paa_imputed_federal_ssi: 0 + +- name: Case 4, ineligible applicant has no imputed federal SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + md_paa_living_arrangement: NONE + households: + household: + members: [person1] + state_code: MD + output: + md_paa_eligible: false + md_paa_imputed_federal_ssi: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_personal_needs_allowance.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_personal_needs_allowance.yaml new file mode 100644 index 00000000000..2e9346bef14 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_personal_needs_allowance.yaml @@ -0,0 +1,111 @@ +# Tests for md_paa_personal_needs_allowance variable. +# Tests parameter values across the timeline (test runner only supports +# January or whole-year periods, so mid-year transitions are checked via +# year-over-year January tests): +# 2009-01-01: $82 (COMAR 07.03.07.04(A)(1); forward-fills until 2022-01-01) +# 2022-01-01: $84 (AT 22-09 FFY22 COLA Mass Mod) +# 2022-07-01: $93 (AT 22-28) +# 2023-07-01: $98 (IM 24-05 June 2023 Mass Modification; appears in 2024-01) +# 2024-07-01: $102 (originating transmittal not located; value corroborated +# by IM 26-04 saying "$102 → $106"; appears in 2025-01) +# 2025-07-01: $106 (IM 26-04 page 2; appears in 2026-01) + +- name: Case 1, 2011 January PNA is $82 (codified in COMAR 07.03.07.04(A)(1)). + period: 2011-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_personal_needs_allowance: 82 + +- name: Case 2, 2022 January PNA is $84 (AT 22-09 FFY22 COLA Mass Mod). + period: 2022-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + # AT 22-09 raised PNA from $82 to $84 effective 2022-01-01, + # then AT 22-28 raised it to $93 on 2022-07-01. + md_paa_personal_needs_allowance: 84 + +- name: Case 3, 2023 PNA reflects $93 (post AT 22-28). + period: 2023-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_personal_needs_allowance: 93 + +- name: Case 4, 2024 January PNA reflects $98 (effective 2023-07-01 per Information Memo 24-05). + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_personal_needs_allowance: 98 + +- name: Case 5, 2025 January PNA reflects $102 (effective 2024-07-01 placeholder). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + # Parameter sets $102 effective 2024-07-01; the originating transmittal + # has not been located, so the date is a placeholder. + md_paa_personal_needs_allowance: 102 + +- name: Case 6, 2026 January PNA reflects $106 (post IM 26-04). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 + ssi_countable_resources: 1_000 + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_personal_needs_allowance: 106 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_provider_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_provider_rate.yaml new file mode 100644 index 00000000000..9697f753e14 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/fia/paa/md_paa_provider_rate.yaml @@ -0,0 +1,178 @@ +# Tests for md_paa_provider_rate variable. +# Rate is determined by md_paa_living_arrangement enum. +# Each tier has at least one test (per testing-patterns: every dimension value). +# Current rates effective 2018-01-01 onwards (per AT 18-11; unchanged through +# every subsequent COLA Mass Mod including AT 23-02). + +- name: Case 1, CARE_HOME_LEVEL_A. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: CARE_HOME_LEVEL_A + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 776 + +- name: Case 2, CARE_HOME_LEVEL_B. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: CARE_HOME_LEVEL_B + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 875 + +- name: Case 3, CARE_HOME_LEVEL_C. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: CARE_HOME_LEVEL_C + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 1_173 + +- name: Case 4, CARE_HOME_LEVEL_D. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: CARE_HOME_LEVEL_D + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 1_376 + +- name: Case 5, ASSISTED_LIVING. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: ASSISTED_LIVING + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 894 + +- name: Case 6, REHAB_RESIDENCE provider rate is zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: REHAB_RESIDENCE + households: + household: + members: [person1] + state_code: MD + output: + # Per PAA Manual §400 and §900.3, MDH pays the provider directly for + # Rehabilitative Residence cases, so PAA's provider rate is zero. PAA + # contributes only the personal needs allowance. + md_paa_provider_rate: 0 + +- name: Case 7, NONE living arrangement returns zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + md_paa_living_arrangement: NONE + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 0 + +# Pre-2018 dates use the COMAR 07.03.07.04(B)(2)/(C)(2) "Effective +# January 1, 2009" schedule. Values forward-fill from 2009 until the +# 2018 update first documented in AT 18-11. +- name: Case 8, pre-2018 period uses COMAR 2009 CARE_HOME_LEVEL_C rate. + period: 2010-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: CARE_HOME_LEVEL_C + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 1_137 + +- name: Case 9, pre-2018 period uses COMAR 2009 ASSISTED_LIVING rate. + period: 2010-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: ASSISTED_LIVING + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 858 + +# Pre/post 2018-01-01 transition: the test runner only supports January +# (or whole-year) periods, so the rate jump first documented in AT 18-11 +# is verified by pairing 2010-01 (Cases 8 and 9 above) with 2018-01 below. +- name: Case 10, 2018-01 CARE_HOME_LEVEL_C jumps to $1,173 (AT 18-11 effective). + period: 2018-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: CARE_HOME_LEVEL_C + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 1_173 + +- name: Case 11, 2018-01 ASSISTED_LIVING jumps to $894 (AT 18-11 effective). + period: 2018-01 + absolute_error_margin: 0.01 + input: + people: + person1: + ssi: 9_600 # gates md_paa_eligible (defined_for on this variable) + md_paa_living_arrangement: ASSISTED_LIVING + households: + household: + members: [person1] + state_code: MD + output: + md_paa_provider_rate: 894 diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa.py new file mode 100644 index 00000000000..5497c7d6c46 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class md_paa(Variable): + value_type = float + entity = Person + label = "Maryland Public Assistance to Adults" + unit = USD + definition_period = MONTH + defined_for = "md_paa_eligible" + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.09", + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.04", + "https://dhs.maryland.gov/documents/FIA/Manuals/Public%20Assistance%20to%20Adults%20%28PAA%29%20Manual/PAA%20900%20Calculation%20of%20Benefits%20rev%2011.22.docx", + "https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/md.html", + ) + + def formula(person, period, parameters): + # Model PAA as a prospective SSI state-supplement cascade: the + # applicant applies for federal SSI, federal SSI is imputed under + # federal rules, and Maryland pays the remaining gap to PAA needs. + # COMAR 07.03.07.08 defines PAA countable income; we approximate it + # with ssi_countable_income because PAA historically mirrors SSI's + # $20 unearned / $65 earned exclusions. PAA-specific income details + # (lump sums, parent contributions, irregular-income carve-outs) + # are not tracked at the moment. + combined_need = person("md_paa_total_cost_of_care", period) + available_resources = add( + person, + period, + ["ssi_countable_income", "md_paa_imputed_federal_ssi"], + ) + return max_(combined_need - available_resources, 0) diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_eligible.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_eligible.py new file mode 100644 index 00000000000..67b2dd8ac95 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_eligible.py @@ -0,0 +1,93 @@ +from policyengine_us.model_api import * + + +class md_paa_eligible(Variable): + value_type = bool + entity = Person + label = "Maryland PAA eligible" + definition_period = MONTH + defined_for = StateCode.MD + reference = ( + "https://dhs.maryland.gov/documents/FIA/Manuals/Public%20Assistance%20to%20Adults%20%28PAA%29%20Manual/PAA%20300%20Technical%20Eligibility%20rev%2011.22.docx", + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.03", + ) + + def formula(person, period, parameters): + # COMAR 07.03.07.03(A)(2): applicants must be aged, blind, or + # disabled and receive SSI, SSDI, or other federal cash benefit + # on the basis of those criteria. SSI and SSDI receipt already + # implies categorical qualification, so the aged/blind/disabled + # gate only applies to the broader OASI / survivor and the + # §300.5 / COMAR 07.03.07.03(G)(1) pending-application pathway, + # which under COMAR additionally requires DHS to verify ABD + # status before granting interim PAA — narrower than §300.5 + # standing alone. COMAR 07.03.07.03(A)(3) ("would-be SSI-eligible + # except for income") is captured through the same + # md_paa_pending_federal_benefit input — we don't auto-detect + # income-denied SSI applicants at the moment, so the caller must + # set the flag manually. + receives_ssi = person("ssi", period) > 0 + ssdi = person("social_security_disability", period) + receives_ssdi = ssdi > 0 + is_categorically_qualifying = person( + "is_ssi_aged_blind_disabled", period.this_year + ) + # `social_security` is the OASDI sum (retirement + survivors + + # disability + dependents). Subtract SSDI so the OASI branch only + # fires for non-SSDI Social Security receipt — SSDI already covers + # itself via `receives_ssdi`. + non_ssdi_oasi = person("social_security", period) - ssdi + receives_other_oasdi_qualifying = ( + non_ssdi_oasi > 0 + ) & is_categorically_qualifying + pending_federal_benefit = ( + person("md_paa_pending_federal_benefit", period) + & is_categorically_qualifying + ) + receives_federal_cash = ( + receives_ssi + | receives_ssdi + | receives_other_oasdi_qualifying + | pending_federal_benefit + ) + # PAA Manual §500: $2,000 resource limit. Each person's resources + # are evaluated against the individual limit independently — the + # couple limit ($3,000) is not used because PAA scopes eligibility + # per recipient (one assistance unit per person), not per couple. + # PAA's resource base also includes real property, money on hand, + # trusts, and transfer-of-asset penalties — those refinements are + # not tracked at the moment, so we approximate via + # ssi_countable_resources. + ssi_resource_limit = parameters( + period + ).gov.ssa.ssi.eligibility.resources.limit.individual + ssi_resources = person("ssi_countable_resources", period.this_year) + resource_eligible = ssi_resources <= ssi_resource_limit + living_arrangement = person("md_paa_living_arrangement", period) + in_facility = living_arrangement != living_arrangement.possible_values.NONE + # MDH Rehabilitative Residence is a Title XIX medical-treatment- + # facility setting per PAA Manual §900.3, so federal SSI is capped + # at $30/mo per 42 USC § 1382(e)(1)(A). The caller must set + # `ssi_lives_in_medical_treatment_facility` and + # `ssi_medicaid_pays_majority_of_care` upstream so federal SSI is + # computed correctly. + is_rehab = ( + living_arrangement == living_arrangement.possible_values.REHAB_RESIDENCE + ) + federal_la = person("ssi_federal_living_arrangement", period.this_year) + is_medical_facility = ( + federal_la == federal_la.possible_values.MEDICAL_TREATMENT_FACILITY + ) + # Bidirectional: REHAB iff SSI medical-facility. A CARE Home recipient + # with the SSI medical-facility flag set would have federal SSI capped + # at $30/mo and produce a wrong PAA cascade; conversely, REHAB without + # the flag set would skip the cap. Either inconsistency makes the + # person ineligible so the inputs are surfaced rather than silently + # producing the wrong amount. + facility_consistent = is_rehab == is_medical_facility + return ( + receives_federal_cash + & resource_eligible + & in_facility + & facility_consistent + ) diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_imputed_federal_ssi.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_imputed_federal_ssi.py new file mode 100644 index 00000000000..dac5d85a381 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_imputed_federal_ssi.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class md_paa_imputed_federal_ssi(Variable): + value_type = float + entity = Person + label = "Maryland PAA imputed federal SSI" + unit = USD + definition_period = MONTH + defined_for = "md_paa_eligible" + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.03", + "https://www.law.cornell.edu/uscode/text/42/1382#e_1_A", + ) + + def formula(person, period, parameters): + return max_(person("uncapped_ssi", period), 0) diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_living_arrangement.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_living_arrangement.py new file mode 100644 index 00000000000..cf70d2748e9 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_living_arrangement.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class MDPAALivingArrangement(Enum): + # CARE Home is the current term per PAA Manual §300.7.B; AT 23-02 + # page 3 still uses the legacy "Project Home Level *" wording. + CARE_HOME_LEVEL_A = "CARE Home Level A" + CARE_HOME_LEVEL_B = "CARE Home Level B" + CARE_HOME_LEVEL_C = "CARE Home Level C" + CARE_HOME_LEVEL_D = "CARE Home Level D" + ASSISTED_LIVING = "Licensed Assisted Living" + REHAB_RESIDENCE = "MDH Rehabilitative Residence" + NONE = "None" + + +class md_paa_living_arrangement(Variable): + value_type = Enum + entity = Person + label = "Maryland PAA living arrangement" + definition_period = MONTH + defined_for = StateCode.MD + possible_values = MDPAALivingArrangement + default_value = MDPAALivingArrangement.NONE + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.04", + "https://dhs.maryland.gov/documents/FIA/Manuals/Public%20Assistance%20to%20Adults%20%28PAA%29%20Manual/PAA%20300%20Technical%20Eligibility%20rev%2011.22.docx", + "https://dhs.maryland.gov/documents/FIA/Manuals/Public%20Assistance%20to%20Adults%20%28PAA%29%20Manual/PAA%20900%20Calculation%20of%20Benefits%20rev%2011.22.docx", + "https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2023/23-02%20AT%20-%20COLA%20Mass%20Mod%20FFY23.pdf#page=3", + ) diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_pending_federal_benefit.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_pending_federal_benefit.py new file mode 100644 index 00000000000..8492f7fa052 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_pending_federal_benefit.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class md_paa_pending_federal_benefit(Variable): + value_type = bool + entity = Person + label = "Maryland PAA pending federal cash benefit applicant" + definition_period = MONTH + defined_for = StateCode.MD + default_value = False + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.03", + "https://dhs.maryland.gov/documents/FIA/Manuals/Public%20Assistance%20to%20Adults%20%28PAA%29%20Manual/PAA%20300%20Technical%20Eligibility%20rev%2011.22.docx", + ) diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_personal_needs_allowance.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_personal_needs_allowance.py new file mode 100644 index 00000000000..b484221b307 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_personal_needs_allowance.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class md_paa_personal_needs_allowance(Variable): + value_type = float + entity = Person + label = "Maryland PAA personal needs allowance" + unit = USD + definition_period = MONTH + defined_for = "md_paa_eligible" + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.04", + "https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2023/23-02%20AT%20-%20COLA%20Mass%20Mod%20FFY23.pdf#page=3", + "https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2026/26-04%20IM%202025%20PNA%20Increase.pdf#page=2", + "https://dhs.maryland.gov/documents/FIA/Manuals/Public%20Assistance%20to%20Adults%20%28PAA%29%20Manual/PAA%20900%20Calculation%20of%20Benefits%20rev%2011.22.docx", + ) + adds = ["gov.states.md.dhs.fia.paa.personal_needs_allowance"] diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_provider_rate.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_provider_rate.py new file mode 100644 index 00000000000..60d882805e1 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_provider_rate.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class md_paa_provider_rate(Variable): + value_type = float + entity = Person + label = "Maryland PAA provider rate" + unit = USD + definition_period = MONTH + defined_for = "md_paa_eligible" + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.04", + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.09", + "https://dhs.maryland.gov/documents/FIA/Action%20Transmittals-AT%20-%20Information%20Memo-IM/AT-IM2023/23-02%20AT%20-%20COLA%20Mass%20Mod%20FFY23.pdf#page=3", + ) + + def formula(person, period, parameters): + living_arrangement = person("md_paa_living_arrangement", period) + return parameters(period).gov.states.md.dhs.fia.paa.provider_rate[ + living_arrangement + ] diff --git a/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_total_cost_of_care.py b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_total_cost_of_care.py new file mode 100644 index 00000000000..c6a49939237 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/fia/paa/md_paa_total_cost_of_care.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class md_paa_total_cost_of_care(Variable): + value_type = float + entity = Person + label = "Maryland PAA total cost of care" + unit = USD + definition_period = MONTH + defined_for = "md_paa_eligible" + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.07.09", + "https://dhs.maryland.gov/documents/FIA/Manuals/Public%20Assistance%20to%20Adults%20%28PAA%29%20Manual/PAA%20900%20Calculation%20of%20Benefits%20rev%2011.22.docx", + ) + adds = ["md_paa_provider_rate", "md_paa_personal_needs_allowance"] 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 4c7705cf267..1c46467f44e 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,6 +26,7 @@ def formula(spm_unit, period, parameters): "hi_oss", "la_oss", # Louisiana benefits "ma_state_supplement", # Massachusetts benefits + "md_paa", # Maryland benefits "wa_ssp", # Washington benefits "mi_ssp", # Michigan benefits "me_ssp", # Maine benefits