diff --git a/changelog.d/md-meap.added.md b/changelog.d/md-meap.added.md new file mode 100644 index 00000000000..c655dad75ae --- /dev/null +++ b/changelog.d/md-meap.added.md @@ -0,0 +1 @@ +Add Maryland MEAP regular heating assistance for state FY25 to FY27. diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/adult_age.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/adult_age.yaml new file mode 100644 index 00000000000..be420e07cb1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/adult_age.yaml @@ -0,0 +1,12 @@ +description: Maryland treats members below this age as children, who count in the household regardless of immigration status and whose earnings are excluded, under the Maryland Energy Assistance Program. +values: + 2025-07-01: 18 +metadata: + unit: year + period: year + label: Maryland MEAP adult age + reference: + - title: OHEP Operations Manual (May 2025), ineligible household members + href: https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=108 + - title: COMAR 07.03.21.04E(3), excluded earnings of a child or full-time student + href: https://regs.maryland.gov/us/md/exec/comar/07.03.21.04#E(3) diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/fpg_rate.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/fpg_rate.yaml new file mode 100644 index 00000000000..7bb9f139362 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/fpg_rate.yaml @@ -0,0 +1,12 @@ +description: Maryland uses this poverty guideline share for income eligibility below the large-household cutoff under the Maryland Energy Assistance Program. +values: + 2024-07-01: 2 +metadata: + unit: /1 + period: year + label: Maryland MEAP poverty guideline rate + reference: + - title: FY2026 OHEP Income Guidelines + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf + - title: FY2025 MEAP Benefit Matrix, income band table + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/fpg_year_lag.yaml new file mode 100644 index 00000000000..83cbb74204a --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/fpg_year_lag.yaml @@ -0,0 +1,14 @@ +description: Maryland uses the poverty guideline from this many years before the model year under the Maryland Energy Assistance Program. +# Inferred: no sheet states the lag. The FY2026 limits equal twice the 2025 +# poverty guideline and the FY25 band tops twice the 2024 guideline. +values: + 2024-07-01: 1 +metadata: + unit: year + period: year + label: Maryland MEAP poverty guideline year lag + reference: + - title: FY2026 OHEP Income Guidelines + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf + - title: FY2025 MEAP Benefit Matrix, income band table + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/smi_min_size.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/smi_min_size.yaml new file mode 100644 index 00000000000..7c616ca157a --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/smi_min_size.yaml @@ -0,0 +1,10 @@ +description: Maryland uses state median income instead of poverty guidelines starting at this household size under the Maryland Energy Assistance Program. +values: + 2025-07-01: 11 +metadata: + unit: person + period: year + label: Maryland MEAP SMI minimum household size + reference: + - title: FY2026 OHEP Income Guidelines + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/smi_rate.yaml new file mode 100644 index 00000000000..7dbb7ba329d --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/eligibility/smi_rate.yaml @@ -0,0 +1,12 @@ +description: Maryland uses this state median income share for large households under the Maryland Energy Assistance Program. +values: + 2025-07-01: 0.6 +metadata: + unit: /1 + period: year + label: Maryland MEAP SMI rate + reference: + - title: FY2026 OHEP Income Guidelines + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf + - title: ACF LIHEAP IM 2025-02, Attachment 4, 60 percent SMI by household size, PDF pages 2, 5 + href: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/income/sources/earned.yaml new file mode 100644 index 00000000000..880ebc76a3f --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/income/sources/earned.yaml @@ -0,0 +1,18 @@ +description: Maryland uses these sources as earned income under the Maryland Energy Assistance Program. +# Self-employment and farm sources are the model's net inputs; no further +# business-expense deduction is applied. +values: + 2025-07-01: + - employment_income + - self_employment_income + - sstb_self_employment_income + - farm_operations_income +metadata: + unit: list + period: year + label: Maryland MEAP earned sources + reference: + - title: COMAR 07.03.21.04D(1)-(2), countable earned income + href: https://regs.maryland.gov/us/md/exec/comar/07.03.21.04#D(1) + - title: OHEP Operations Manual (May 2025), Attachment A, countable income + href: https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=111 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/income/sources/unearned.yaml new file mode 100644 index 00000000000..7e6713978b9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/income/sources/unearned.yaml @@ -0,0 +1,36 @@ +description: Maryland uses these sources as unearned income under the Maryland Energy Assistance Program. +# Social Security and railroad retirement benefits are counted in the formula, +# net of the Medicare premium (COMAR 07.03.21.04D(3), D(26) and E(20)). +values: + 2025-07-01: + - ssi + - tanf + - ordinary_dividend_income + - interest_income + - estate_income + - pension_income + # Military retirement pay is a separate input from the pension inputs that + # pension_income adds, so both are listed. Its survivor payments are not + # separable from survivor_benefits, so a survivor annuity could count twice. + - military_retirement_pay + - survivor_benefits + - retirement_distributions + - child_support_received + - alimony_income + - workers_compensation + - unemployment_compensation + - veterans_benefits + - strike_benefits + - rental_income + - farm_rent_income +metadata: + unit: list + period: year + label: Maryland MEAP unearned sources + reference: + - title: COMAR 07.03.21.04D, countable income, and E, exclusions + href: https://regs.maryland.gov/us/md/exec/comar/07.03.21.04#D(1) + - title: OHEP Operations Manual (May 2025), Attachments A and B, PDF pages 111, 112 + href: https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=111 + - title: FY2026 LIHEAP State Plan, section 1.9, PDF pages 6, 7 + href: https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/electricity.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/electricity.yaml new file mode 100644 index 00000000000..f7887c95ae5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/electricity.yaml @@ -0,0 +1,34 @@ +description: Maryland provides this annual regular heating payment for electricity by benefit level under the Maryland Energy Assistance Program. +1: + 2024-07-01: 102 + 2025-07-01: 100 +2: + 2024-07-01: 102 + 2025-07-01: 100 +3: + 2024-07-01: 102 + 2025-07-01: 100 +4: + 2024-07-01: 102 + 2025-07-01: 100 +5: + 2024-07-01: 102 + 2025-07-01: 100 +6: + 2024-07-01: 102 + 2025-07-01: 100 +7: + 2024-07-01: 25 +metadata: + unit: currency-USD + period: year + label: Maryland MEAP electricity heating payments + breakdown: + - range(1, 8) + reference: + - title: FY2025 MEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf + - title: FY26 MEAP Benefit Matrix + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf + - title: FY27 MEAP Benefit Matrices, statewide table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/gas.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/gas.yaml new file mode 100644 index 00000000000..3865d5e623b --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/gas.yaml @@ -0,0 +1,40 @@ +description: Maryland provides this annual regular heating payment for natural gas by benefit level under the Maryland Energy Assistance Program. +1: + 2024-07-01: 301 + 2025-07-01: 550 + 2026-07-01: 700 +2: + 2024-07-01: 241 + 2025-07-01: 475 + 2026-07-01: 665 +3: + 2024-07-01: 210 + 2025-07-01: 400 + 2026-07-01: 630 +4: + 2024-07-01: 181 + 2025-07-01: 360 + 2026-07-01: 560 +5: + 2024-07-01: 150 + 2025-07-01: 300 + 2026-07-01: 455 +6: + 2024-07-01: 102 + 2025-07-01: 225 + 2026-07-01: 315 +7: + 2024-07-01: 25 +metadata: + unit: currency-USD + period: year + label: Maryland MEAP gas heating payments + breakdown: + - range(1, 8) + reference: + - title: FY2025 MEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf + - title: FY26 MEAP Benefit Matrix + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf + - title: FY27 MEAP Benefit Matrices, statewide table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/oil.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/oil.yaml new file mode 100644 index 00000000000..902b25f751d --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/oil.yaml @@ -0,0 +1,40 @@ +description: Maryland provides this annual regular heating payment for oil or kerosene by benefit level under the Maryland Energy Assistance Program. +1: + 2024-07-01: 750 + 2025-07-01: 1_100 + 2026-07-01: 1_225 +2: + 2024-07-01: 600 + 2025-07-01: 990 + 2026-07-01: 1_160 +3: + 2024-07-01: 525 + 2025-07-01: 880 + 2026-07-01: 1_080 +4: + 2024-07-01: 450 + 2025-07-01: 770 + 2026-07-01: 980 +5: + 2024-07-01: 375 + 2025-07-01: 650 + 2026-07-01: 795 +6: + 2024-07-01: 102 + 2025-07-01: 225 + 2026-07-01: 550 +7: + 2024-07-01: 25 +metadata: + unit: currency-USD + period: year + label: Maryland MEAP oil heating payments + breakdown: + - range(1, 8) + reference: + - title: FY2025 MEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf + - title: FY26 MEAP Benefit Matrix + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf + - title: FY27 MEAP Benefit Matrices, statewide table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/propane.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/propane.yaml new file mode 100644 index 00000000000..dc489b88ac4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/propane.yaml @@ -0,0 +1,40 @@ +description: Maryland provides this annual regular heating payment for propane by benefit level under the Maryland Energy Assistance Program. +1: + 2024-07-01: 644 + 2025-07-01: 1_000 + 2026-07-01: 1_325 +2: + 2024-07-01: 515 + 2025-07-01: 930 + 2026-07-01: 1_255 +3: + 2024-07-01: 450 + 2025-07-01: 830 + 2026-07-01: 1_190 +4: + 2024-07-01: 386 + 2025-07-01: 725 + 2026-07-01: 1_060 +5: + 2024-07-01: 321 + 2025-07-01: 600 + 2026-07-01: 860 +6: + 2024-07-01: 102 + 2025-07-01: 225 + 2026-07-01: 595 +7: + 2024-07-01: 25 +metadata: + unit: currency-USD + period: year + label: Maryland MEAP propane heating payments + breakdown: + - range(1, 8) + reference: + - title: FY2025 MEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf + - title: FY26 MEAP Benefit Matrix + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf + - title: FY27 MEAP Benefit Matrices, statewide table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/wood_coal.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/wood_coal.yaml new file mode 100644 index 00000000000..cc191cf38d5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/amount/wood_coal.yaml @@ -0,0 +1,39 @@ +description: Maryland provides this annual regular heating payment for wood or coal by benefit level under the Maryland Energy Assistance Program. +1: + 2024-07-01: 418 + 2025-07-01: 550 +2: + 2024-07-01: 334 + 2025-07-01: 475 + 2026-07-01: 520 +3: + 2024-07-01: 292 + 2025-07-01: 400 + 2026-07-01: 495 +4: + 2024-07-01: 250 + 2025-07-01: 360 + 2026-07-01: 440 +5: + 2024-07-01: 209 + 2025-07-01: 300 + 2026-07-01: 355 +6: + 2024-07-01: 102 + 2025-07-01: 225 + 2026-07-01: 245 +7: + 2024-07-01: 25 +metadata: + unit: currency-USD + period: year + label: Maryland MEAP wood and coal heating payments + breakdown: + - range(1, 8) + reference: + - title: FY2025 MEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf + - title: FY26 MEAP Benefit Matrix + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf + - title: FY27 MEAP Benefit Matrices, statewide table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/garrett_multiplier.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/garrett_multiplier.yaml new file mode 100644 index 00000000000..dd0b2004671 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/garrett_multiplier.yaml @@ -0,0 +1,14 @@ +description: Maryland sets this multiplier for regular heating payments in Garrett County under the Maryland Energy Assistance Program. +values: + 2024-07-01: 1.1 +metadata: + unit: /1 + period: year + label: Maryland MEAP Garrett multiplier + reference: + - title: FY2025 LIHEAP State Plan, section 2.5 + href: https://liheapch.acf.gov/docs/2025/state-plans/MD_Plan_2025.pdf#page=11 + - title: FY2026 LIHEAP State Plan, section 2.5 + href: https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=11 + - title: FY27 MEAP Benefit Matrices, Garrett County table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/income_level.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/income_level.yaml new file mode 100644 index 00000000000..f22565f336b --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/income_level.yaml @@ -0,0 +1,41 @@ +description: Maryland uses these inclusive poverty-ratio band tops to assign regular heating payment levels under the Maryland Energy Assistance Program. +brackets: +- threshold: + 2024-07-01: -.inf + amount: + 2024-07-01: 1 +- threshold: + 2024-07-01: 0.25 + amount: + 2024-07-01: 2 +- threshold: + 2024-07-01: 0.5 + amount: + 2024-07-01: 3 +- threshold: + 2024-07-01: 1 + amount: + 2024-07-01: 4 +- threshold: + 2024-07-01: 1.5 + amount: + 2024-07-01: 5 +- threshold: + 2024-07-01: 2 + # Over 200 percent is Level 7, the nominal level in nominal_level.yaml; + # the two must agree. + amount: + 2024-07-01: 7 +metadata: + type: single_amount + threshold_unit: /1 + amount_unit: /1 + period: year + label: Maryland MEAP income payment levels + reference: + - title: FY2025 MEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf + - title: FY26 MEAP Benefit Matrix + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf + - title: FY27 MEAP Benefit Matrices, statewide table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/nominal_level.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/nominal_level.yaml new file mode 100644 index 00000000000..aca28f78950 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/nominal_level.yaml @@ -0,0 +1,17 @@ +description: Maryland sets this payment level for categorically eligible households above 200 percent of the poverty guideline under the Maryland Energy Assistance Program. +# Level 7 is also the top bracket of income_level.yaml; the two must agree. +values: + 2024-07-01: 7 +metadata: + unit: /1 + period: year + label: Maryland MEAP nominal payment level + reference: + - title: FY2025 MEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf + - title: FY26 MEAP Benefit Matrix + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf + - title: FY27 MEAP Benefit Matrices, statewide table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 + - title: OHEP Operations Manual (May 2025), section 6.0, nominal benefit + href: https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=63 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/regional_counties.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/regional_counties.yaml new file mode 100644 index 00000000000..e6916cf8feb --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/regional_counties.yaml @@ -0,0 +1,13 @@ +description: Maryland uses the regional heating multiplier in these counties under the Maryland Energy Assistance Program. +values: + 2024-07-01: + - GARRETT_COUNTY_MD +metadata: + unit: list + period: year + label: Maryland MEAP regional multiplier counties + reference: + - title: FY2025 LIHEAP State Plan, section 2.5 + href: https://liheapch.acf.gov/docs/2025/state-plans/MD_Plan_2025.pdf#page=11 + - title: FY2026 LIHEAP State Plan, section 2.5 + href: https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=11 diff --git a/policyengine_us/parameters/gov/states/md/dhs/meap/payment/subsidized_level.yaml b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/subsidized_level.yaml new file mode 100644 index 00000000000..5dc4bd2644b --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/dhs/meap/payment/subsidized_level.yaml @@ -0,0 +1,16 @@ +description: Maryland sets this payment level for subsidized or submetered households under the Maryland Energy Assistance Program. +values: + 2024-07-01: 6 +metadata: + unit: /1 + period: year + label: Maryland MEAP subsidized payment level + reference: + - title: FY2025 MEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf + - title: FY26 MEAP Benefit Matrix + href: https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf + - title: FY27 MEAP Benefit Matrices, statewide table, PDF page 1 + href: https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 + - title: FY2026 LIHEAP State Plan, section 2.3, renters in subsidized housing + href: https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=9 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index f5ffc832e76..35ed6f1d2a5 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -808,7 +808,7 @@ programs: category: Benefits agency: HHS status: partial - coverage: DC, Riverside County, MA, IL, IN, KS, KY, MS, NC, NE, TX + coverage: DC, Riverside County, MA, IL, IN, KS, KY, MD, MS, NC, NE, TX state_implementations: - state: DC status: complete @@ -852,6 +852,14 @@ programs: parameter_prefix: gov.states.ky.dcbs.liheap verified_years: "2025-2026" notes: FY2025-FY2026 regular heating only, from the published benefit workbooks. Crisis and cooling assistance are out of scope. + - state: MD + status: partial + name: Maryland MEAP + full_name: Maryland Energy Assistance Program + variable: md_meap + parameter_prefix: gov.states.md.dhs.meap + verified_years: "2025-2027" + notes: FY25-FY27 regular heating only, with the fuel tables, the Garrett County multiplier and the subsidized and nominal levels. The SNAP nominal payment, cooling, EUSP, arrearage, crisis and equipment benefits are out of scope. - state: MS status: partial name: Mississippi LIHEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_categorically_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_categorically_eligible.yaml new file mode 100644 index 00000000000..128b8870e17 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_categorically_eligible.yaml @@ -0,0 +1,39 @@ +# Sources for the expected values in this file: +# - OHEP Operations Manual (May 2025), page 62, section 6.0 Categorical Eligibility: +# https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=62 +# - FY2026 LIHEAP State Plan, page 5 (categorical eligibility by program): +# https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=5 + +- name: Case 1, SNAP, TCA or SSI receipt each confers categorical eligibility. + period: 2026 + input: + state_code: [MD, MD, MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + # $200 a month of SNAP, $300 a month of TCA, and SSI at the 2026 federal rate + # of $994 a month. + snap: [2_400, 0, 0, 0] + tanf: [0, 3_600, 0, 0] + ssi: [0, 0, 11_928, 0] + veterans_benefits: [0, 0, 0, 1_000] + output: + # Manual page 62: households participating in SNAP, TANF, SSI or means-tested VA + # programs are categorically eligible, and any member's receipt qualifies the + # household. The fourth household has veterans benefits only: the model cannot + # tell whether they are means-tested, so they do not qualify it (documented + # limitation). + md_meap_categorically_eligible: [true, true, true, false] + +- name: Case 2, TCA entitlement that is not taken up does not confer categorical eligibility. + period: 2026 + input: + state_code: [MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS] + md_tca: [1_200, 1_200] + takes_up_tanf_if_eligible: [false, true] + snap: [0, 0] + ssi: [0, 0] + output: + # State Plan page 5: a household is categorically income-eligible if a member + # receives the benefit on an ongoing basis. The first household is entitled to + # TCA but does not receive it; the second receives it. + md_meap_categorically_eligible: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_eligible.yaml new file mode 100644 index 00000000000..fce98b98b2d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_eligible.yaml @@ -0,0 +1,124 @@ +# Sources for the expected values in this file: +# - FY2026 OHEP Income Guidelines (one page): +# https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf +# - OHEP Operations Manual (May 2025), pages 16 (general eligibility), 38 (categorical +# eligibility denials), 39 (automatic denials), 62-63 (categorical eligibility) and +# 108 (ineligible members): +# https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=16 +# - FY2026 LIHEAP State Plan, page 9 (renters in subsidized housing): +# https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=9 +# - COMAR 07.03.21.03 (residence): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.03 +# - COMAR 07.03.21.04C (nonqualified members): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.04 +# - COMAR 07.03.21.06D(3) (denials): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.06 + +- name: Case 1, one-person household at and one dollar above the annual income limit. + period: 2026 + input: + state_code: [MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_150, 1_150] + md_meap_countable_income: [31_300, 31_301] + md_meap_categorically_eligible: [false, false] + output: + # Income Guidelines, annual 200% FPG table, size 1: $31,300. Manual page 16: + # income "equal to or less than the established income guidelines" is eligible. + md_meap_eligible: [true, false] + +- name: Case 2, categorical eligibility waives the income test but not the heating cost. + period: 2026 + input: + state_code: [MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_150, 0] + md_meap_countable_income: [40_000, 40_000] + md_meap_categorically_eligible: [true, true] + output: + # Manual page 62: a categorically eligible household stays eligible above 200% + # FPL; page 63: other eligibility rules are unchanged, and page 16 requires, for + # MEAP, that responsibility for heating costs is established. The second + # household heats with gas but has no gas bill. + md_meap_eligible: [true, false] + +- name: Case 3, heat included in rent is denied in subsidized housing, with or without categorical eligibility. + period: 2026 + input: + state_code: [MD, MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + # Set directly to show that the subsidized heat-in-rent denial does not depend on + # a reported heating cost. + has_heating_expense: [true, true, true] + md_meap_countable_income: [0, 0, 0] + md_meap_categorically_eligible: [false, false, true] + heat_expense_included_in_rent: [true, true, true] + receives_housing_assistance: [false, true, true] + output: + # Manual page 16: heating costs may be paid as an undesignated component of rent. + # COMAR 07.03.21.06D(3)(i) and manual page 39 deny an applicant in public or + # subsidized housing where heat is included in the rent. Manual page 38: + # categorical eligibility applications "may be denied for other eligibility + # issues", so the third household is denied too. + md_meap_eligible: [true, false, false] + +- name: Case 4, a qualified member is required even with categorical eligibility. + period: 2026 + input: + state_code: MD + heating_type: NATURAL_GAS + gas_expense: 1_150 + md_meap_countable_income: 0 + md_meap_categorically_eligible: true + immigration_status: UNDOCUMENTED + output: + # Manual page 108: the household must have at least one eligible (citizen or + # qualified alien) member; COMAR 07.03.21.04C(1) likewise does not count the + # member. + md_meap_eligible: false + +- name: Case 5, other states receive no Maryland benefit. + period: 2026 + input: + state_code: VA + heating_type: NATURAL_GAS + gas_expense: 1_150 + md_meap_countable_income: 0 + md_meap_categorically_eligible: false + output: + # COMAR 07.03.21.03A(1): the household must reside in Maryland. + md_meap_eligible: false + +- name: Case 6, public housing tenant who pays the heating bill is eligible, heat in rent is not. + period: 2026 + input: + state_code: [MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [950, 0] + heat_expense_included_in_rent: [false, true] + is_in_public_housing: [true, true] + md_meap_countable_income: [19_500, 19_500] + md_meap_categorically_eligible: [false, false] + output: + # State Plan page 9: applicants in subsidized housing must show that they pay + # their own heating costs. COMAR 07.03.21.06D(3)(i) and manual page 39 deny an + # applicant in public housing where heat is included in the rent. + md_meap_eligible: [true, false] + +- name: Case 7, eleven-member household at and one dollar above the 60 percent SMI limit. + period: 2026 + input: + state_code: [MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [2_100, 2_100] + md_meap_household_size: [11, 11] + md_meap_countable_income: [135_930, 135_931] + md_meap_categorically_eligible: [false, false] + output: + # Income Guidelines footnote: "Households of 11+ must be based on 60% of the State + # Median Income." The limit is 60% of the FFY2026 Maryland four-person median + # income, floor(0.6 x $154,117) = $92,470, times the 45 CFR 96.85(b) size factor + # for eleven, 1.47 (52% + 5 x 16% + 5 x 3%): floor($135,930.90) = $135,930, the + # row ACF LIHEAP IM 2025-02 Attachment 4 (page 5) prints. $135,931 is over the + # limit although it is below 200% of the eleven-person guideline ($141,300). + md_meap_eligible: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_household_size.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_household_size.yaml new file mode 100644 index 00000000000..cf06f1fce1d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_household_size.yaml @@ -0,0 +1,93 @@ +# Sources for the expected values in this file: +# - OHEP Operations Manual (May 2025), page 108: "Children under 18 are always +# counted in the household, regardless of citizenship status"; ineligible adults +# "are not counted in the household number but their income is included"; and +# "the household must have at least one eligible member": +# https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=108 +# - COMAR 07.03.21.04C(1), which would not count any nonqualified member (the model +# follows the manual, the operating rule): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.04 + +# Four two-person households, each with a gas bill, no income and no SNAP, TCA or +# SSI: +# - citizen parent and undocumented child: both count, size 2, eligible; +# - undocumented parent and citizen child: only the child counts, size 1, eligible +# because the child is a qualified member; +# - undocumented parent and undocumented child: the child counts, size 1, but no +# member is eligible, so the household is not; +# - two undocumented adults: neither counts, size 0, not eligible. +- name: Case 1, children under 18 count regardless of status and nonqualified adults do not. + period: 2026 + input: + people: + parent1: + age: 40 + ssi: 0 + child1: + age: 5 + immigration_status: UNDOCUMENTED + ssi: 0 + parent2: + age: 40 + immigration_status: UNDOCUMENTED + ssi: 0 + child2: + age: 5 + ssi: 0 + parent3: + age: 40 + immigration_status: UNDOCUMENTED + ssi: 0 + child3: + age: 5 + immigration_status: UNDOCUMENTED + ssi: 0 + adult4a: + age: 40 + immigration_status: UNDOCUMENTED + ssi: 0 + adult4b: + age: 38 + immigration_status: UNDOCUMENTED + ssi: 0 + spm_units: + spm_unit1: + members: [parent1, child1] + heating_type: NATURAL_GAS + gas_expense: 1_150 + snap: 0 + tanf: 0 + spm_unit2: + members: [parent2, child2] + heating_type: NATURAL_GAS + gas_expense: 1_150 + snap: 0 + tanf: 0 + spm_unit3: + members: [parent3, child3] + heating_type: NATURAL_GAS + gas_expense: 1_150 + snap: 0 + tanf: 0 + spm_unit4: + members: [adult4a, adult4b] + heating_type: NATURAL_GAS + gas_expense: 1_150 + snap: 0 + tanf: 0 + households: + household1: + members: [parent1, child1] + state_code: MD + household2: + members: [parent2, child2] + state_code: MD + household3: + members: [parent3, child3] + state_code: MD + household4: + members: [adult4a, adult4b] + state_code: MD + output: + md_meap_household_size: [2, 1, 1, 0] + md_meap_eligible: [true, true, false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_income_limit.yaml new file mode 100644 index 00000000000..343b3005147 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_income_limit.yaml @@ -0,0 +1,53 @@ +# Sources for the expected values in this file: +# - FY2026 OHEP Income Guidelines (one page), annual 200% FPG table and the 60% SMI +# footnote for households of 11 or more: +# https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf +# - FY2025 MEAP Benefit Matrix, income band table (monthly tops of the 151-200% FPL +# band, Case 3): +# https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf +# - ACF LIHEAP IM 2025-02, Attachment 4, page 5 (60% SMI rows for sizes 7 to 12): +# https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=5 + +- name: Case 1, published annual limits for sizes one to ten. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD, MD, MD, MD] + md_meap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + output: + # Income Guidelines FY2026, annual table: sizes 1 to 8 print $31,300, $42,300, + # $53,300, $64,300, $75,300, $86,300, $97,300 and $108,300, each 200% of the + # 2025 HHS poverty guideline ($15,650 plus $5,500 per additional person). Sizes + # 9 and 10 have no printed row; 200% of the guideline gives $119,300 and + # $130,300, where the page's "for each additional HH member add $11,004" line + # would give $4 and $8 more; the model follows the 200% rate (noted in the + # variable documentation). The 60% SMI rule from size 11 is Case 2. + md_meap_income_limit: [31_300, 42_300, 53_300, 64_300, 75_300, 86_300, 97_300, 108_300, 119_300, 130_300] + +- name: Case 2, sizes eleven and twelve use 60 percent of state median income. + period: 2026 + input: + state_code: [MD, MD] + md_meap_household_size: [11, 12] + output: + # Income Guidelines footnote: "Households of 11+ must be based on 60% of the State + # Median Income." 60% of the FFY2026 Maryland four-person median income, + # floor(0.6 x $154,117) = $92,470, times the 45 CFR 96.85(b) size factors (52% + + # 5 x 16% + 3% per member above six): + # size 11: 1.47 x $92,470 = $135,930.90, floored to $135,930; + # size 12: 1.50 x $92,470 = $138,705. + # Both rows are printed in ACF LIHEAP IM 2025-02 Attachment 4 (page 5). 200% of + # the ten-person guideline ($130,300) is below 60% SMI for ten ($133,156), so + # the switch at eleven is the federal ceiling at work. + md_meap_income_limit: [135_930, 138_705] + +- name: Case 3, FY25 limits in period 2025 are twice the 2024 guideline. + period: 2025 + input: + state_code: [MD, MD, MD] + md_meap_household_size: [1, 4, 8] + output: + # FY2025 MEAP Benefit Matrix, income band table, monthly tops of the 151-200% FPL + # band: size 1 $2,510, size 4 $5,200, size 8 $8,787. Twice the 2024 HHS poverty + # guideline ($15,060 plus $5,380 per additional person): $30,120, $62,400 and + # $105,440, whose twelfths are $2,510, $5,200 and $8,786.67 (printed rounded). + md_meap_income_limit: [30_120, 62_400, 105_440] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_countable_earned_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_countable_earned_income.yaml new file mode 100644 index 00000000000..086b4570149 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_countable_earned_income.yaml @@ -0,0 +1,23 @@ +# Source for the expected values in this file: COMAR 07.03.21.04D(1)-(2) (countable +# wages and net self-employment income) and E(3) (excluded earnings of a child +# under 18 or a full-time student): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.04 + +- name: Case 1, child and full-time student earnings are excluded, adults' count from age 18, and business losses floor at zero. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD] + age: [17, 18, 18, 40, 40, 40] + is_full_time_student: [false, true, false, true, false, false] + employment_income: [12_000, 12_000, 12_000, 12_000, 12_000, 12_000] + self_employment_income: [1_000, 1_000, 1_000, 1_000, 1_000, -1_000] + sstb_self_employment_income: [600, 600, 600, 600, 600, 600] + farm_operations_income: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200] + output: + # COMAR 07.03.21.04E(3): employment income of a child younger than 18 or of a + # full-time student is not countable: the 17-year-old, the 18-year-old student + # and the 40-year-old student each count $0. An 18-year-old who is not a student + # and a 40-year-old count $12,000 wages + $1,000 + $600 + $1,200 net + # self-employment (D(1), D(2)) = $14,800. With a $1,000 business loss the loss + # is floored at $0 for that source: $12,000 + $0 + $600 + $1,200 = $13,800. + md_meap_countable_earned_income: [0, 0, 14_800, 0, 14_800, 13_800] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_countable_income.yaml new file mode 100644 index 00000000000..a66b8799fa3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_countable_income.yaml @@ -0,0 +1,105 @@ +# Sources for the expected values in this file: +# - COMAR 07.03.21.04D (countable income sources), E(13) and F (court-ordered child +# support paid is deducted), D(3), D(26) and E(20) (Social Security and railroad +# retirement less the Medicare deduction): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.04 +# - FY2026 LIHEAP State Plan, section 1.9 (page 6): SSA benefits "Excluding MediCare +# deduction": +# https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=6 + +- name: Case 1, every modeled unearned source counts and court-ordered support is deducted. + period: 2026 + input: + state_code: MD + md_meap_countable_earned_income: 10_000 + social_security: 12_000 + medicare_part_b_premium: 0 + railroad_benefits: 600 + pension_income: 1_200 + military_retirement_pay: 1_800 + survivor_benefits: 300 + retirement_distributions: 2_400 + interest_income: 120 + ordinary_dividend_income: 240 + estate_income: 360 + rental_income: 1_200 + farm_rent_income: 240 + child_support_received: 600 + alimony_income: 480 + workers_compensation: 720 + unemployment_compensation: 840 + veterans_benefits: 960 + strike_benefits: 120 + ssi: 0 + tanf: 0 + child_support_expense: 2_400 + output: + # COMAR 07.03.21.04D: $10,000 earnings + $12,000 Social Security (D(3), with no + # Medicare premium to deduct) + $600 railroad retirement (D(26)) + $1,200 pensions + # + $1,800 military retirement pay (D(12)) + $300 survivor benefits (D(12), + # D(13), D(18)) + $2,400 retirement account disbursements (D(13)) + $120 interest + # (D(6)) + $240 dividends (D(5)) + $360 estate income (D(8)) + $1,200 rental + + # $240 farm rental income (D(2)) + $600 child support (D(14)) + $480 alimony + # (D(15)) + $720 workers' compensation (D(16)) + $840 unemployment (D(17)) + + # $960 veterans benefits (D(18)) + $120 strike funds (D(24)) = $34,180; less + # $2,400 court-ordered child support paid (E(13), F) = $31,780. + md_meap_countable_income: 31_780 + +- name: Case 2, the support deduction cannot make countable income negative. + period: 2026 + input: + state_code: MD + md_meap_countable_earned_income: 0 + ssi: 0 + tanf: 0 + child_support_expense: 10_000 + output: + # COMAR 07.03.21.04F deducts verified support from gross income; with no income + # the result is floored at $0. + md_meap_countable_income: 0 + +- name: Case 3, TCA counts only when it is taken up. + period: 2026 + input: + state_code: [MD, MD] + md_tca: [1_200, 1_200] + takes_up_tanf_if_eligible: [false, true] + ssi: [0, 0] + output: + # COMAR 07.03.21.04D(10): temporary cash assistance is countable. The first + # household is entitled to $1,200 of TCA but does not receive it, $0; the second + # receives it, $1,200. + md_meap_countable_income: [0, 1_200] + +- name: Case 4, Social Security counts net of the Medicare Part B premium the person pays. + period: 2026 + input: + state_code: [MD, MD] + age: [70, 70] + social_security: [32_000, 32_000] + medicare_part_b_premium: [2_435, 0] + ssi: [0, 0] + tanf: [0, 0] + output: + # COMAR 07.03.21.04D(3) counts "Social Security income less Medicare payment + # deduction" and E(20) excludes the Medicare payments deducted from the check; + # plan 1.9 checks "Excluding MediCare deduction". $32,000 - $2,435 = $29,565 for + # the retiree who pays the premium; $32,000 when a Medicare Savings Program + # pays it. + md_meap_countable_income: [29_565, 32_000] + +- name: Case 5, a rental or estate loss is floored at zero and does not offset earnings. + period: 2026 + input: + state_code: [MD, MD] + md_meap_countable_earned_income: [33_000, 33_000] + rental_income: [-3_000, 3_000] + estate_income: [-1_000, 0] + ssi: [0, 0] + tanf: [0, 0] + output: + # COMAR 07.03.21.04D(2) treats self-employment and rental income as one item, + # and plan 1.8 (page 6) counts gross income, so each source is floored at zero + # like the earned sources: $33,000 + $0 + $0 = $33,000, and $33,000 + $3,000 = + # $36,000. + md_meap_countable_income: [33_000, 36_000] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_fpg.yaml new file mode 100644 index 00000000000..12a9ea929f9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/income/md_meap_fpg.yaml @@ -0,0 +1,28 @@ +# Source for the expected values in this file: FY2026 OHEP Income Guidelines (one +# page), whose annual 200% FPG limits are twice the prior calendar year's HHS poverty +# guideline: +# https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf + +- name: Case 1, the prior-year guideline follows the requested year when parameters backfill. + period: 2022 + input: + state_code: MD + heating_type: NATURAL_GAS + md_meap_household_size: 2 + output: + # One-year lag from the FY2026 guidelines applied to 2022: the 2021 HHS poverty + # guideline for two people, $12,880 + $4,540 = $17,420. Years before FY25 are + # unverified backfilled estimates. + md_meap_fpg: 17_420 + +- name: Case 2, the 2026 guideline is the 2025 HHS poverty guideline behind the FY2026 limits. + period: 2026 + input: + state_code: [MD, MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + md_meap_household_size: [1, 4, 8] + output: + # Income Guidelines, annual 200% FPG table: size 1 $31,300, size 4 $64,300, + # size 8 $108,300; half of each is the 2025 HHS poverty guideline ($15,650 plus + # $5,500 per additional person): $15,650, $32,150, $54,150. + md_meap_fpg: [15_650, 32_150, 54_150] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/integration.yaml new file mode 100644 index 00000000000..5502ba76d25 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/integration.yaml @@ -0,0 +1,513 @@ +# Sources for the expected values in this file: +# - FY26 MEAP Benefit Matrix (one page), "the matrix" below: +# https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf +# - FY2026 OHEP Income Guidelines (one page), "the Income Guidelines" below; the annual +# 200% FPG limits are twice the 2025 HHS poverty guideline ($15,650 plus $5,500 per +# additional person), which is the guideline the levels are measured against: +# https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf +# - FY2026 LIHEAP State Plan, pages 5 (categorical eligibility), 6 (SSA benefits +# "Excluding MediCare deduction"), 9 (renters in subsidized housing) and 11 (item +# 2.5, Garrett County multiplier): +# https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=11 +# - OHEP Operations Manual (May 2025), pages 16 (general eligibility), 39 (automatic +# denials), 62-63 (categorical eligibility and the nominal benefit) and 108 +# (ineligible members and children under 18): +# https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=62 +# - FY27 MEAP Benefit Matrices, page 1 (Garrett County table, half-up rounding): +# https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 +# - COMAR 07.03.21.04 (household members and countable income): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.04 +# - COMAR 07.03.21.06D(3) (denials): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.06 +# Every case states that the household does not receive SNAP, TCA or SSI unless the +# case is about that receipt (Case 12 lets SNAP compute). + +- name: Case 1, mixed-status family counts the child under the manual rule and the child's income. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 20_000 + ssi: 0 + person2: + age: 5 + immigration_status: UNDOCUMENTED + child_support_received: 1_000 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_150 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: MD + county: BALTIMORE_COUNTY_MD + output: + # Manual page 108: "Children under 18 are always counted in the household, + # regardless of citizenship status", so the undocumented child counts (COMAR + # 07.03.21.04C(1) would not count the child; the manual is the operating rule). + md_meap_household_size: 2 + # $20,000 wages (D(1)) + $1,000 child support received by the child (D(14)). + md_meap_countable_income: 21_000 + # Income Guidelines, annual table, size 2: $42,300. + md_meap_income_limit: 42_300 + # $42,300 / 2, the 2025 two-person guideline. + md_meap_fpg: 21_150 + # $21,000 / $21,150 = 99%: matrix Level 3 (51-100% FPL). + md_meap_level: 3 + # $21,000 is under the $42,300 limit; the parent is a qualified member; the gas + # bill establishes a heating cost (manual page 16). + md_meap_eligible: true + # Matrix, Gas row, Level 3: $400. + md_meap: 400 + +- name: Case 2, SSI recipient living with a working adult above 200 percent in subsidized Garrett County housing gets the nominal grant. + period: 2026 + input: + people: + person1: + age: 45 + employment_income: 36_000 + ssi: 0 + person2: + age: 23 + # SSI at the 2026 federal rate of $994 a month. + ssi: 11_928 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: PROPANE + bottled_gas_expense: 1_900 + receives_housing_assistance: true + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: MD + county: GARRETT_COUNTY_MD + output: + md_meap_household_size: 2 + # State Plan page 5 and manual page 62: a member receiving SSI makes the household + # categorically eligible. + md_meap_categorically_eligible: true + # $36,000 wages (COMAR 07.03.21.04D(1)) + $11,928 SSI (D(4)). + md_meap_countable_income: 47_928 + # Income Guidelines, annual table, size 2: $42,300; the guideline is half of it. + md_meap_income_limit: 42_300 + md_meap_fpg: 21_150 + # $47,928 / $21,150 = 227%: matrix Level 7 (Over 200% FPL). Manual page 63 pays + # categorically eligible households above 200% FPL the nominal benefit, which + # takes precedence over the Level 6 subsidized column. + md_meap_level: 7 + # Manual page 62: the household stays eligible above 200% FPL; it pays its own + # propane bill, so the subsidized heat-in-rent denial does not apply. + md_meap_eligible: true + # Matrix, Propane row, Level 7: $25. The Garrett County multiplier (State Plan + # item 2.5, page 11) leaves the nominal grant flat, as every Level 7 cell of the + # FY27 Garrett County table (page 1) is $25. + md_meap: 25 + +- name: Case 3, unsubsidized heat in rent with a known fuel uses the fuel row at the income level. + period: 2026 + input: + state_code: MD + age: 40 + employment_income: 10_000 + snap: 0 + tanf: 0 + ssi: 0 + heat_expense_included_in_rent: true + heating_type: FUEL_OIL + output: + # $10,000 wages (COMAR 07.03.21.04D(1)). + md_meap_countable_income: 10_000 + # $10,000 / $15,650 = 64%: matrix Level 3 (51-100% FPL). + md_meap_level: 3 + # Manual page 16: heating costs paid as an undesignated component of rent qualify; + # the household is not in subsidized housing, so COMAR 07.03.21.06D(3)(i) does + # not apply. + md_meap_eligible: true + # Matrix, Oil row, Level 3: $880. Paying a landlord-billed home from the ordinary + # income level and fuel row is an inference; no published source states the level + # for heat included in rent outside subsidized housing (unverified). + md_meap: 880 + +- name: Case 4, couple with two children at Level 5. + period: 2026 + input: + people: + person1: + age: 38 + employment_income: 38_000 + ssi: 0 + person2: + age: 36 + employment_income: 14_000 + ssi: 0 + person3: + age: 9 + ssi: 0 + person4: + age: 5 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + heating_type: NATURAL_GAS + gas_expense: 1_300 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + county: ANNE_ARUNDEL_COUNTY_MD + output: + # Four citizens (manual page 108). + md_meap_household_size: 4 + # $38,000 + $14,000 wages (D(1)). + md_meap_countable_income: 52_000 + # Income Guidelines, annual table, size 4: $64,300; the guideline is half of it. + md_meap_income_limit: 64_300 + md_meap_fpg: 32_150 + md_meap_categorically_eligible: false + # $52,000 / $32,150 = 162%: matrix Level 5 (151-200% FPL). + md_meap_level: 5 + # $52,000 is under the $64,300 limit and the gas bill establishes a heating cost. + md_meap_eligible: true + # Matrix, Gas row, Level 5: $300. + md_meap: 300 + +- name: Case 5, retired couple in Garrett County with propane heat receives the multiplied Level 4 grant. + period: 2026 + input: + people: + person1: + age: 68 + social_security_retirement: 16_800 + ssi: 0 + person2: + age: 66 + social_security_retirement: 9_600 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: PROPANE + bottled_gas_expense: 2_300 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: MD + county: GARRETT_COUNTY_MD + output: + md_meap_household_size: 2 + # $16,800 + $9,600 Social Security (COMAR 07.03.21.04D(3)), net of the Medicare + # Part B premium: at this income a Medicare Savings Program pays both spouses' + # premiums, so the model's out-of-pocket premium is $0 and nothing is deducted + # (Case 11 shows the deduction). + md_meap_countable_income: 26_400 + # Income Guidelines, annual table, size 2: $42,300; the guideline is half of it. + md_meap_income_limit: 42_300 + md_meap_fpg: 21_150 + # $26,400 / $21,150 = 125%: matrix Level 4 (101-150% FPL). + md_meap_level: 4 + md_meap_eligible: true + # Matrix, Propane row, Level 4: $725, times the 1.1 Garrett County multiplier + # (State Plan item 2.5, page 11) = $797.50, rounded half up to $798 (rounding + # follows the FY27 Garrett County table, page 1). + md_meap: 798 + +- name: Case 6, family over the income limit without categorical eligibility receives nothing. + period: 2026 + input: + people: + person1: + age: 41 + employment_income: 46_000 + ssi: 0 + person2: + age: 39 + employment_income: 24_000 + ssi: 0 + person3: + age: 7 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + gas_expense: 1_250 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2, person3] + state_code: MD + county: FREDERICK_COUNTY_MD + output: + md_meap_household_size: 3 + # $46,000 + $24,000 wages (COMAR 07.03.21.04D(1)). + md_meap_countable_income: 70_000 + # Income Guidelines, annual table, size 3: $53,300. + md_meap_income_limit: 53_300 + md_meap_categorically_eligible: false + # $70,000 is over the $53,300 limit; manual page 39: over-income applications + # without categorical eligibility are denied. + md_meap_eligible: false + md_meap: 0 + +- name: Case 7, public housing tenant who pays the gas bill receives the Level 6 grant. + period: 2026 + input: + people: + person1: + age: 31 + employment_income: 19_500 + ssi: 0 + person2: + age: 6 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 950 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: MD + county: BALTIMORE_CITY_MD + is_in_public_housing: true + output: + md_meap_household_size: 2 + # $19,500 wages (COMAR 07.03.21.04D(1)). + md_meap_countable_income: 19_500 + # Income Guidelines, annual table, size 2: $42,300; the guideline is half of it. + md_meap_income_limit: 42_300 + md_meap_fpg: 21_150 + # $19,500 / $21,150 = 92% would be Level 3, but State Plan page 9 gives renters in + # subsidized housing a lower benefit level because a utility allowance is in + # their subsidy: matrix Level 6 (Subsidized/Sub metered). + md_meap_level: 6 + # State Plan page 9: the tenant pays the heating bill directly, so the public + # housing heat-in-rent denial (COMAR 07.03.21.06D(3)(i)) does not apply. + md_meap_eligible: true + # Matrix, Gas row, Level 6: $225. + md_meap: 225 + +- name: Case 8, eleven-member household above the 60 percent SMI limit but below 200 percent of the guideline is over income. + period: 2026 + input: + people: + person1: + age: 46 + employment_income: 58_000 + ssi: 0 + person2: + age: 44 + employment_income: 41_000 + ssi: 0 + person3: + age: 22 + employment_income: 27_300 + ssi: 0 + person4: + age: 71 + social_security_retirement: 11_700 + ssi: 0 + person5: {age: 17, ssi: 0} + person6: {age: 15, ssi: 0} + person7: {age: 13, ssi: 0} + person8: {age: 11, ssi: 0} + person9: {age: 9, ssi: 0} + person10: {age: 6, ssi: 0} + person11: {age: 3, ssi: 0} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + heating_type: NATURAL_GAS + gas_expense: 2_100 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + state_code: MD + county: PRINCE_GEORGE_S_COUNTY_MD + output: + md_meap_household_size: 11 + # $58,000 + $41,000 + $27,300 wages (COMAR 07.03.21.04D(1)) + $11,700 Social + # Security (D(3); a Medicare Savings Program pays the grandparent's premium at + # this income, so nothing is deducted) = $138,000. + md_meap_countable_income: 138_000 + # 2025 HHS poverty guideline for eleven: $15,650 + 10 x $5,500 = $70,650. + md_meap_fpg: 70_650 + # Income Guidelines footnote: "Households of 11+ must be based on 60% of the State + # Median Income": floor(0.6 x $154,117) = $92,470 (FFY2026 Maryland four-person + # median income), times the 45 CFR 96.85(b) size factor 1.47 = $135,930. + md_meap_income_limit: 135_930 + md_meap_categorically_eligible: false + # $138,000 is over the $135,930 limit although it is below 200% of the guideline + # ($141,300); manual page 39: over-income applications without categorical + # eligibility are denied. + md_meap_eligible: false + md_meap: 0 + +- name: Case 9, heat included in rent with an unknown fuel is eligible but unpaid. + period: 2026 + input: + state_code: MD + county: BALTIMORE_CITY_MD + age: 29 + employment_income: 24_000 + snap: 0 + tanf: 0 + ssi: 0 + heat_expense_included_in_rent: true + heating_type: UNSPECIFIED + output: + # $24,000 wages (COMAR 07.03.21.04D(1)). + md_meap_countable_income: 24_000 + # Income Guidelines, annual table, size 1: $31,300. + md_meap_income_limit: 31_300 + # Manual page 16: heating costs paid as an undesignated component of rent qualify; + # the household is not in subsidized housing. + md_meap_eligible: true + # Every matrix row is a fuel, so no amount can be read for an unknown fuel: the + # $0 is a coverage gap, not a denial, and the unspecified default is tracked in + # #9754. + md_meap: 0 + +- name: Case 10, categorically eligible eleven-member household above the 60 percent SMI limit but below 200 percent is paid at Level 5. + period: 2026 + input: + people: + person1: + age: 46 + employment_income: 58_000 + ssi: 0 + person2: + age: 44 + employment_income: 41_000 + ssi: 0 + person3: + age: 22 + employment_income: 27_300 + ssi: 0 + person4: + age: 71 + # SSI at the 2026 federal rate of $994 a month. + ssi: 11_928 + person5: {age: 17, ssi: 0} + person6: {age: 15, ssi: 0} + person7: {age: 13, ssi: 0} + person8: {age: 11, ssi: 0} + person9: {age: 9, ssi: 0} + person10: {age: 6, ssi: 0} + person11: {age: 3, ssi: 0} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + heating_type: NATURAL_GAS + gas_expense: 2_100 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + state_code: MD + county: PRINCE_GEORGE_S_COUNTY_MD + output: + md_meap_household_size: 11 + # State Plan page 5 and manual page 62: the grandparent's SSI makes the household + # categorically eligible. + md_meap_categorically_eligible: true + # $58,000 + $41,000 + $27,300 wages (COMAR 07.03.21.04D(1)) + $11,928 SSI (D(4)) + # = $138,228. + md_meap_countable_income: 138_228 + # As in Case 8: $70,650 guideline and $135,930 limit. + md_meap_fpg: 70_650 + md_meap_income_limit: 135_930 + # $138,228 / $70,650 = 196%: matrix Level 5 (151-200% FPL). The nominal Level 7 + # applies only above 200% FPL (manual page 63), not above the SMI limit. + md_meap_level: 5 + # Manual page 62: the household remains eligible above the income limit when a + # member receives a qualifying benefit. + md_meap_eligible: true + # Matrix, Gas row, Level 5: $300. + md_meap: 300 + +- name: Case 11, retiree whose Social Security is just over the limit qualifies once the Medicare premium is deducted. + period: 2026 + input: + state_code: MD + county: BALTIMORE_COUNTY_MD + age: 70 + social_security_retirement: 32_000 + snap: 0 + tanf: 0 + ssi: 0 + heating_type: NATURAL_GAS + gas_expense: 1_150 + output: + # $32,000 of Social Security is over the $31,300 one-person limit (Income + # Guidelines), but COMAR 07.03.21.04D(3) counts it "less Medicare payment + # deduction" and State Plan page 6 checks "Excluding MediCare deduction". The + # model's 2026 Part B premium for this retiree is $202.90 a month, $2,434.80 a + # year, and no Medicare Savings Program pays it at this income: + # $32,000 - $2,434.80 = $29,565.20. + md_meap_countable_income: 29_565.2 + md_meap_income_limit: 31_300 + # $29,565.20 / $15,650 = 189%: matrix Level 5 (151-200% FPL). + md_meap_level: 5 + md_meap_eligible: true + # Matrix, Gas row, Level 5: $300. + md_meap: 300 + +# Nothing is pinned here: SNAP, TCA and SSI are all computed. Wages are given as +# employment_income_before_lsr, the input the TANF earned-income list reads (the +# MD TCA tests use it too); employment_income derives from it. With $1,500 a month +# of wages the model's TCA countable earnings exceed the two-person grant, so TCA +# is $0, while SNAP is positive. +- name: Case 12, SNAP computed by the model makes a working parent categorically eligible. + period: 2026 + input: + people: + person1: + age: 30 + employment_income_before_lsr: 18_000 + person2: + age: 6 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_150 + households: + household: + members: [person1, person2] + state_code: MD + county: BALTIMORE_CITY_MD + output: + # The model's own SNAP for a parent with $18,000 of wages and one child is + # positive, which State Plan page 5 and manual page 62 treat as categorical + # eligibility; the model's TCA for the same household is $0. + md_meap_categorically_eligible: true + # $18,000 wages (COMAR 07.03.21.04D(1)); no TCA to add under D(10). + md_meap_countable_income: 18_000 + # $18,000 / $21,150 = 85%: matrix Level 3 (51-100% FPL). + md_meap_level: 3 + md_meap_eligible: true + # Matrix, Gas row, Level 3: $400. + md_meap: 400 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/md_meap.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/md_meap.yaml new file mode 100644 index 00000000000..5ed59cf4e52 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/md_meap.yaml @@ -0,0 +1,256 @@ +# Sources for the expected values in this file: +# - FY26 MEAP Benefit Matrix (one page), "the matrix" below: +# https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf +# - FY2025 MEAP Benefit Matrix (one page; Cases 11 and 12): +# https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf +# - FY27 MEAP Benefit Matrices, page 1 (statewide and Garrett County tables; Cases +# 13 and 14, the Oil/Kerosene row label and the Garrett rounding): +# https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1 +# - FY2026 OHEP Income Guidelines (one page): +# https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf +# - FY2026 LIHEAP State Plan, item 2.5 on page 11 (Garrett County multiplier): +# https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=11 +# - FY2025 LIHEAP State Plan, item 2.5 on page 11 (the same multiplier): +# https://liheapch.acf.gov/docs/2025/state-plans/MD_Plan_2025.pdf#page=11 +# - OHEP Operations Manual (May 2025), page 6 (solar subscriptions), page 38 +# (categorical eligibility denials) and page 63 (nominal benefit above 200% FPL): +# https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=63 +# - COMAR 07.03.21.03 (eligibility): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.03 +# - COMAR 07.03.21.06 (denials): +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.06 +# A model year reads the parameters at January 1, inside state FY (July to June) of +# the same number: period 2025 is FY25, 2026 is FY26 and 2027 is FY27. + +- name: Case 1, electric heat at each FY26 matrix level. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD] + heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] + md_meap_eligible: [true, true, true, true, true, true, true] + md_meap_level: [1, 2, 3, 4, 5, 6, 7] + county: [BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD] + output: + # Matrix, Electric row, Levels 1 to 7: $100, $100, $100, $100, $100, $100, $25. + md_meap: [100, 100, 100, 100, 100, 100, 25] + +- name: Case 2, natural gas heat at each FY26 matrix level. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + md_meap_eligible: [true, true, true, true, true, true, true] + md_meap_level: [1, 2, 3, 4, 5, 6, 7] + county: [BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD] + output: + # Matrix, Gas row, Levels 1 to 7: $550, $475, $400, $360, $300, $225, $25. + md_meap: [550, 475, 400, 360, 300, 225, 25] + +- name: Case 3, fuel oil heat at each FY26 matrix level. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD] + heating_type: [FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL] + md_meap_eligible: [true, true, true, true, true, true, true] + md_meap_level: [1, 2, 3, 4, 5, 6, 7] + county: [BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD] + output: + # Matrix, Oil row, Levels 1 to 7: $1,100, $990, $880, $770, $650, $225, $25. + md_meap: [1_100, 990, 880, 770, 650, 225, 25] + +- name: Case 4, propane heat at each FY26 matrix level. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD] + heating_type: [PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE] + md_meap_eligible: [true, true, true, true, true, true, true] + md_meap_level: [1, 2, 3, 4, 5, 6, 7] + county: [BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD] + output: + # Matrix, Propane row, Levels 1 to 7: $1,000, $930, $830, $725, $600, $225, $25. + md_meap: [1_000, 930, 830, 725, 600, 225, 25] + +- name: Case 5, wood heat at each FY26 matrix level. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD] + heating_type: [WOOD, WOOD, WOOD, WOOD, WOOD, WOOD, WOOD] + md_meap_eligible: [true, true, true, true, true, true, true] + md_meap_level: [1, 2, 3, 4, 5, 6, 7] + county: [BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD] + output: + # Matrix, Wood/Coal row, Levels 1 to 7: $550, $475, $400, $360, $300, $225, $25, + # the same as the FY26 Gas row (the FY25 and FY27 rows differ). + md_meap: [550, 475, 400, 360, 300, 225, 25] + +- name: Case 6, Garrett County multiplier rounds half up and leaves the nominal grant flat. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD] + county: [GARRETT_COUNTY_MD, GARRETT_COUNTY_MD, GARRETT_COUNTY_MD, GARRETT_COUNTY_MD, GARRETT_COUNTY_MD] + heating_type: [NATURAL_GAS, PROPANE, FUEL_OIL, FUEL_OIL, FUEL_OIL] + md_meap_eligible: [true, true, true, true, true] + md_meap_level: [2, 4, 6, 1, 7] + output: + # State Plan item 2.5 (page 11) applies a 1.1 multiplier to MEAP benefits for + # Garrett County residents. Matrix cells times 1.1: + # Gas, Level 2: $475 x 1.1 = $522.50, rounded half up to $523. + # Propane, Level 4: $725 x 1.1 = $797.50, rounded half up to $798. + # Oil, Level 6: $225 x 1.1 = $247.50, rounded half up to $248. + # Oil, Level 1: $1,100 x 1.1 = $1,210. + # Oil, Level 7: the $25 nominal grant, no multiplier. + # No FY26 Garrett County dollar table is published. Half-up rounding and the flat + # Level 7 amount follow the FY27 Garrett County table (FY27 matrices, page 1), + # where every Level 7 cell is $25. + md_meap: [523, 798, 248, 1_210, 25] + +- name: Case 7, kerosene, coal and solar rows and fuels without a matrix row. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD] + heating_type: [KEROSENE, COAL, SOLAR, OTHER, UNSPECIFIED, NONE] + md_meap_eligible: [true, true, true, true, true, true] + md_meap_level: [1, 1, 1, 1, 1, 1] + output: + # Matrix, Level 1 cells. Kerosene is paid from the Oil row, $1,100 (the FY26 matrix + # has no kerosene row; the FY27 matrix, page 1, labels the row Oil/Kerosene). + # Coal is paid from the Wood/Coal row, $550. A grid-tied solar home pays an + # electricity bill (manual page 6 lists solar subscriptions), so it is paid from + # the Electric row, $100. Other fuels and no heating have no matrix row, $0. An + # unspecified fuel pays $0 as a coverage gap: the amount depends on the fuel and + # the unspecified default is tracked in #9754. + md_meap: [1_100, 550, 100, 0, 0, 0] + +- name: Case 8, submetered home at Level 6 and the assisted living denial with and without categorical eligibility. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD] + county: [MONTGOMERY_COUNTY_MD, MONTGOMERY_COUNTY_MD, MONTGOMERY_COUNTY_MD, MONTGOMERY_COUNTY_MD, MONTGOMERY_COUNTY_MD] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_150, 1_150, 1_150, 1_150, 1_150] + md_meap_countable_income: [0, 0, 0, 40_000, 40_000] + md_meap_categorically_eligible: [false, false, false, true, true] + md_meap_dwelling_type: [STANDARD, SUB_METERED, ASSISTED_LIVING, SUB_METERED, ASSISTED_LIVING] + output: + # COMAR 07.03.21.06D(3)(k) denies an applicant who resides in an assisted living + # facility. The fourth household is over the $31,300 one-person limit (Income + # Guidelines) but categorically eligible, so the income test is waived. The fifth + # is categorically eligible too, but manual page 38 lets such applications be + # denied "for other eligibility issues", so assisted living still denies it. + md_meap_eligible: [true, true, false, true, false] + # Matrix columns: no income is Level 1 (0-25% FPL); a submetered home is Level 6 + # (Subsidized/Sub metered); $40,000 for one person is 256% of the $15,650 + # guideline, Level 7 (Over 200% FPL), which the manual (page 63) pays as the + # nominal benefit ahead of the submetered level. + md_meap_level: [1, 6, 1, 7, 7] + # Matrix, Gas row: Level 1 $550, Level 6 $225, Level 7 $25. Ineligible: $0. + md_meap: [550, 225, 0, 25, 0] + +- name: Case 9, Maryland household and Virginia household in the same simulation. + period: 2026 + input: + state_code: [MD, VA] + county: [BALTIMORE_COUNTY_MD, FAIRFAX_COUNTY_VA] + age: [34, 34] + employment_income: [20_000, 20_000] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_150, 1_150] + # Neither household receives SNAP, TCA or SSI. + snap: [0, 0] + tanf: [0, 0] + ssi: [0, 0] + output: + # Maryland: one person with $20,000 of wages is under the $31,300 annual limit for + # size 1 (Income Guidelines) and at 128% of the $15,650 guideline ($31,300 / 2), + # the matrix's Level 4 column (101-150% FPL). Matrix, Gas row, Level 4: $360. + # Virginia: MEAP requires that the household resides in Maryland + # (COMAR 07.03.21.03A(1)), so the same household pays $0 there. + md_meap: [360, 0] + +# COMAR 07.03.21.04D(2) counts rental-property income after operating expenses: +# https://regs.maryland.gov/us/md/exec/comar/07.03.21.04 +- name: Case 10, farm rental income puts a gas-heating household over the income limit. + period: 2026 + input: + state_code: MD + county: BALTIMORE_COUNTY_MD + age: 45 + employment_income: 24_000 + farm_rent_income: 12_000 + ssi: 0 + tanf: 0 + snap: 0 + heating_type: NATURAL_GAS + gas_expense: 1_200 + output: + # No rental expenses: $24,000 wages + $12,000 farm rents = $36,000. + md_meap_countable_income: 36_000 + # Income Guidelines: the one-person annual limit is $31,300. + md_meap_income_limit: 31_300 + md_meap_categorically_eligible: false + md_meap_eligible: false + md_meap: 0 + +# FY2025 MEAP Benefit Matrix ("*Flat Rates"), Level 1 (0-25% FPL) and Level 6 +# (Subsidized/Sub metered) by row: +# Electric: $102, $102. Gas: $301, $102. Oil: $750, $102. +# Propane: $644, $102. Wood/Coal: $418, $102. +# Level 6 is $102 for every fuel in FY25; the FY25 plan (page 11) prints the $750 +# maximum, the oil Level 1 cell. +- name: Case 11, FY25 matrix rows at Levels 1 and 6 in period 2025. + period: 2025 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD, MD, MD, MD] + county: [BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD] + heating_type: [ELECTRICITY, NATURAL_GAS, FUEL_OIL, PROPANE, WOOD, ELECTRICITY, NATURAL_GAS, FUEL_OIL, PROPANE, WOOD] + md_meap_eligible: [true, true, true, true, true, true, true, true, true, true] + md_meap_level: [1, 1, 1, 1, 1, 6, 6, 6, 6, 6] + output: + md_meap: [102, 301, 750, 644, 418, 102, 102, 102, 102, 102] + +- name: Case 12, FY25 Garrett County multiplier in period 2025. + period: 2025 + input: + state_code: [MD, MD, MD] + county: [GARRETT_COUNTY_MD, GARRETT_COUNTY_MD, GARRETT_COUNTY_MD] + heating_type: [FUEL_OIL, NATURAL_GAS, PROPANE] + md_meap_eligible: [true, true, true] + md_meap_level: [1, 5, 7] + output: + # FY2025 plan item 2.5 (page 11) applies the same 1.1 multiplier. FY25 matrix + # cells times 1.1: Oil, Level 1: $750 x 1.1 = $825. Gas, Level 5: $150 x 1.1 = + # $165. Propane, Level 7: the $25 nominal grant, no multiplier. + md_meap: [825, 165, 25] + +# FY27 MEAP Benefit Matrix, statewide table (page 1), Level 1 and Level 6 by row: +# Electric: $100, $100. Gas: $700, $315. Oil/Kerosene: $1,225, $550. +# Propane: $1,325, $595. Wood/Coal: $550, $245. +- name: Case 13, FY27 matrix rows at Levels 1 and 6 in period 2027. + period: 2027 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD, MD, MD, MD] + county: [BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD, BALTIMORE_COUNTY_MD] + heating_type: [ELECTRICITY, NATURAL_GAS, FUEL_OIL, PROPANE, WOOD, ELECTRICITY, NATURAL_GAS, FUEL_OIL, PROPANE, WOOD] + md_meap_eligible: [true, true, true, true, true, true, true, true, true, true] + md_meap_level: [1, 1, 1, 1, 1, 6, 6, 6, 6, 6] + output: + md_meap: [100, 700, 1_225, 1_325, 550, 100, 315, 550, 595, 245] + +- name: Case 14, FY27 Garrett County table in period 2027. + period: 2027 + input: + state_code: [MD, MD, MD, MD, MD] + county: [GARRETT_COUNTY_MD, GARRETT_COUNTY_MD, GARRETT_COUNTY_MD, GARRETT_COUNTY_MD, GARRETT_COUNTY_MD] + heating_type: [ELECTRICITY, NATURAL_GAS, WOOD, FUEL_OIL, FUEL_OIL] + md_meap_eligible: [true, true, true, true, true] + md_meap_level: [1, 2, 5, 4, 7] + output: + # FY27 Garrett County table (page 1) against the statewide cells times 1.1: + # Electric, Level 1: $100 x 1.1 = $110, printed $110. + # Gas, Level 2: $665 x 1.1 = $731.50, rounded half up to $732, printed $732. + # Wood/Coal, Level 5: $355 x 1.1 = $390.50, rounded half up to $391, printed $391. + # Oil, Level 4: $980 x 1.1 = $1,078. The table prints $1,210 in this one cell + # (1.1 x the FY26 oil Level 1), which no other cell supports; the model keeps + # the plan's multiplier. + # Oil, Level 7: the $25 nominal grant, printed $25. + md_meap: [110, 732, 391, 1_078, 25] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/payment/md_meap_level.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/payment/md_meap_level.yaml new file mode 100644 index 00000000000..5ea1b85fe30 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/payment/md_meap_level.yaml @@ -0,0 +1,54 @@ +# Sources for the expected values in this file: +# - FY26 MEAP Benefit Matrix (one page), column headings: Level 1 0-25% FPL, Level 2 +# 26-50% FPL, Level 3 51-100% FPL, Level 4 101-150% FPL, Level 5 151-200% FPL, +# Level 6 Subsidized/Sub metered, Level 7 Over 200% FPL: +# https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf +# - OHEP Operations Manual (May 2025), page 63 (nominal benefit for categorically +# eligible households above 200% FPL): +# https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=63 +# - FY2026 LIHEAP State Plan, page 9 (lower benefit level in subsidized housing): +# https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=9 +# The $10,000 guideline is a round figure so that the incomes are exact percentages. + +- name: Case 1, income at each poverty band top and one dollar above it. + period: 2026 + input: + state_code: [MD, MD, MD, MD, MD, MD, MD, MD, MD, MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + md_meap_fpg: [10_000, 10_000, 10_000, 10_000, 10_000, 10_000, 10_000, 10_000, 10_000, 10_000, 10_000] + md_meap_countable_income: [0, 2_500, 2_501, 5_000, 5_001, 10_000, 10_001, 15_000, 15_001, 20_000, 20_001] + output: + # Matrix columns by income as a share of the guideline: 0% and 25% are Level 1 + # (0-25%); 25.01% and 50% are Level 2 (26-50%); 50.01% and 100% are Level 3 + # (51-100%); 100.01% and 150% are Level 4 (101-150%); 150.01% and 200% are + # Level 5 (151-200%); 200.01% is Level 7 (Over 200%). Band tops are read as + # inclusive, matching the at-or-below income test. + md_meap_level: [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 7] + +- name: Case 2, housing assistance uses Level 6 unless income is above 200 percent. + period: 2026 + input: + state_code: [MD, MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + md_meap_fpg: [10_000, 10_000, 10_000] + md_meap_countable_income: [0, 20_000, 20_001] + receives_housing_assistance: [true, true, true] + output: + # Matrix: subsidized households are Level 6 (Subsidized/Sub metered) at 0% and at + # 200% of the guideline. At 200.01%, Level 7 (Over 200% FPL): the manual (page + # 63) pays categorically eligible households above 200% FPL a nominal benefit. + md_meap_level: [6, 6, 7] + +- name: Case 3, public housing uses Level 6 unless income is above 200 percent. + period: 2026 + input: + state_code: [MD, MD] + heating_type: [NATURAL_GAS, NATURAL_GAS] + md_meap_fpg: [10_000, 10_000] + md_meap_countable_income: [8_000, 20_001] + is_in_public_housing: [true, true] + output: + # State Plan page 9: renters in subsidized housing receive a lower benefit level + # because a utility allowance is in their subsidy; matrix Level 6 at 80% of the + # guideline. At 200.01%, Level 7 (Over 200% FPL) as in Case 2. + md_meap_level: [6, 7] diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_categorically_eligible.py b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_categorically_eligible.py new file mode 100644 index 00000000000..2b750d71d04 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_categorically_eligible.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class md_meap_categorically_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP categorical income eligibility" + defined_for = StateCode.MD + reference = ( + # PDF pages 11, 62, 63. + "https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=11", + "https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=5", + ) + documentation = ( + "One member's receipt of SNAP, TCA or SSI waives the income test. Means-tested " + "veterans benefits are also legally qualifying, but generic veterans_benefits " + "cannot identify that subset. Recurring receipt in the program year is " + "approximated by annual benefit receipt." + ) + + def formula(spm_unit, period, parameters): + return add(spm_unit, period, ["snap", "tanf", "ssi"]) > 0 diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_eligible.py b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_eligible.py new file mode 100644 index 00000000000..57967995fef --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_eligible.py @@ -0,0 +1,46 @@ +from policyengine_us.model_api import * + + +class md_meap_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP regular heating eligibility" + defined_for = StateCode.MD + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.21.03", + "https://regs.maryland.gov/us/md/exec/comar/07.03.21.06", + # PDF pages 11, 12, 16, 38, 39, 108. + "https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=11", + ) + documentation = ( + "Regular heating has no resource test. Application documentation, emancipation " + "and program-year duplicate awards are not modeled. The regulation permits an " + "annually announced medical-expense waiver, but no such regular-heating waiver " + "was found in the FY2026 plan. At least one qualified member is required; a " + "child counted regardless of status does not satisfy that requirement." + ) + + def formula(spm_unit, period, parameters): + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + dwelling = spm_unit("md_meap_dwelling_type", period) + assisted_living = dwelling == dwelling.possible_values.ASSISTED_LIVING + subsidized = spm_unit( + "receives_housing_assistance", period + ) | spm_unit.household("is_in_public_housing", period) + # Manual page 38: categorical eligibility waives the income test but + # not the other denials. + income_eligible = spm_unit("md_meap_categorically_eligible", period) | ( + spm_unit("md_meap_countable_income", period) + <= spm_unit("md_meap_income_limit", period) + ) + # Manual page 108: the household must have at least one eligible + # (citizen or qualified alien) member. + qualified_member = add(spm_unit, period, ["is_citizen_or_legal_immigrant"]) > 0 + return ( + income_eligible + & qualified_member + & (spm_unit("has_heating_expense", period) | heat_in_rent) + & ~(heat_in_rent & subsidized) + & ~assisted_living + ) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_household_size.py b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_household_size.py new file mode 100644 index 00000000000..8f45c386859 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_household_size.py @@ -0,0 +1,32 @@ +from policyengine_us.model_api import * + + +class md_meap_household_size(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP qualified household size" + defined_for = StateCode.MD + reference = ( + # PDF pages 107, 108. + "https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=108", + "https://regs.maryland.gov/us/md/exec/comar/07.03.21.04", + ) + documentation = ( + "Follows the May 2025 manual (page 108): every child under 18 counts " + "regardless of immigration status, nonqualified adults are excluded from " + "size, and every member's income counts in full. COMAR 07.03.21.04C(1) would " + "exclude every nonqualified member; the manual is the operating rule. SPM " + "membership approximates the energy-sharing household. No SNAP-specific " + "immigration bars apply." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.dhs.meap + person = spm_unit.members + # Manual page 108: "Children under 18 are always counted in the + # household, regardless of citizenship status"; ineligible adults are + # not counted. + child = person("age", period) < p.adult_age + qualified = person("is_citizen_or_legal_immigrant", period) + return spm_unit.sum(qualified | child) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_income_limit.py b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_income_limit.py new file mode 100644 index 00000000000..8a87469af84 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_income_limit.py @@ -0,0 +1,37 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class md_meap_income_limit(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP annual income limit" + unit = USD + defined_for = StateCode.MD + reference = ( + "https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf", + "https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=9", + # PDF pages 2, 5. + "https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=5", + ) + documentation = ( + "The published annual 200% FPG amounts control sizes 1-10 rather than the " + "plan's truncated equivalent SMI percentages or its inconsistent " + "additional-member line. Annual inputs are compared with annual limits; the " + "printed monthly amounts are rounded separately. Sizes 11 and above use 60% " + "SMI and reproduce the dollar rows ACF LIHEAP IM 2025-02 Attachment 4 prints " + "for sizes 7 to 12." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.dhs.meap.eligibility + size = max_(spm_unit("md_meap_household_size", period), 1) + state = spm_unit.household("state_code_str", period) + base = parameters(period).gov.hhs.smi.amount[state] + factor = smi(size, state, period, parameters) / base + # ACF LIHEAP IM 2025-02 Attachment 4 (page 5) floors 60% of the + # four-person SMI, then floors each size's share of it. + smi_limit = np.floor(factor * np.floor(base * p.smi_rate)) + poverty_limit = spm_unit("md_meap_fpg", period) * p.fpg_rate + return where(size >= p.smi_min_size, smi_limit, poverty_limit) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_countable_earned_income.py b/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_countable_earned_income.py new file mode 100644 index 00000000000..c05b0849a69 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_countable_earned_income.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class md_meap_countable_earned_income(Variable): + value_type = float + entity = Person + definition_period = YEAR + label = "Maryland MEAP countable earnings" + unit = USD + defined_for = StateCode.MD + reference = ("https://regs.maryland.gov/us/md/exec/comar/07.03.21.04#E(3)",) + documentation = ( + "Uses existing net business income without an additional expense deduction. " + "MEAP depreciation add-backs are unsupported. Each source is floored at zero, " + "so a loss in one source cannot offset another." + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.md.dhs.meap + earned = 0 + for source in p.income.sources.earned: + earned = earned + max_(person(source, period), 0) + # COMAR 07.03.21.04E(3) excludes the employment income of a child + # younger than 18 or of a full-time student. + counted = (person("age", period) >= p.adult_age) & ~person( + "is_full_time_student", period + ) + return where(counted, earned, 0) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_countable_income.py b/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_countable_income.py new file mode 100644 index 00000000000..555c22f672a --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_countable_income.py @@ -0,0 +1,62 @@ +from policyengine_us.model_api import * + + +class md_meap_countable_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP countable household income" + unit = USD + defined_for = StateCode.MD + reference = ( + "https://regs.maryland.gov/us/md/exec/comar/07.03.21.04", + # PDF pages 111, 112. + "https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=111", + # PDF pages 6, 7. + "https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=6", + ) + documentation = ( + "Annual income approximates the 30-day application period. All members' income " + "counts in full. Follows COMAR where the checklists differ: nonrecurring lump " + "sums and AmeriCorps/VISTA are excluded although the manual and plan count " + "them; interest and dividends count although the plan leaves them unchecked; " + "strike funds without employee contributions count although manual " + "Attachment B excludes them. Reported child support paid is assumed " + "court-ordered. Veterans income approximates pension benefits and strike " + "income is assumed not employee-funded. Social Security and railroad " + "retirement count net of the computed Medicare Part B premium. Each source is " + "floored at zero, so a rental or estate loss does not offset other income. " + "TDAP, royalties, gifts, loans, special allowances and home-care receipts " + "cannot be isolated reliably." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.dhs.meap.income + person = spm_unit.members + # COMAR 07.03.21.04D(3), D(26) and E(20) count Social Security and + # railroad retirement benefits less the Medicare payment deduction, and + # plan 1.9 (page 6) checks "Excluding MediCare deduction". The computed + # medicare_part_b_premium is the out-of-pocket Part B premium, zero when + # a Medicare Savings Program pays it. + benefits = spm_unit.sum( + max_( + person("social_security", period) + + person("railroad_benefits", period) + - person("medicare_part_b_premium", period), + 0, + ) + ) + # COMAR 07.03.21.04D(2) treats self-employment and rental income as one + # item and plan 1.8 (page 6) counts gross income, so each unearned + # source is floored like the earned sources: a loss in one source + # cannot offset another. The TANF source applies take-up to Maryland + # TCA entitlement. + unearned = 0 + for source in p.sources.unearned: + unearned = unearned + max_(add(spm_unit, period, [source]), 0) + income = ( + add(spm_unit, period, ["md_meap_countable_earned_income"]) + + benefits + + unearned + ) + return max_(income - add(spm_unit, period, ["child_support_expense"]), 0) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_fpg.py b/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_fpg.py new file mode 100644 index 00000000000..c4a8e1381da --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/income/md_meap_fpg.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class md_meap_fpg(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP applicable federal poverty guideline" + unit = USD + defined_for = StateCode.MD + reference = ( + "https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/Income-Guidelines-FY2026-Updated-7.9.2025.pdf", + "https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf", + ) + documentation = ( + "The FY2026 limits are twice the 2025 poverty guideline and the FY25 matrix " + "band tops twice the 2024 guideline, so the guideline of the calendar year " + "before the model year applies; no sheet states the lag." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.dhs.meap.eligibility + size = max_(spm_unit("md_meap_household_size", period), 1) + state_group = spm_unit.household("state_group_str", period) + return fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/md_meap.py b/policyengine_us/variables/gov/states/md/dhs/meap/md_meap.py new file mode 100644 index 00000000000..415c7f62a08 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/md_meap.py @@ -0,0 +1,67 @@ +from policyengine_us.model_api import * + + +class md_meap(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP regular heating benefit" + unit = USD + defined_for = "md_meap_eligible" + reference = ( + "https://liheapch.acf.gov/docs/2025/benefits-matricies/MD_BenefitMatrix_2025.pdf", + "https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf", + "https://dhs.maryland.gov/documents/OHEP/FY27-MEAP-Benefit-Matrices.pdf#page=1", + "https://liheapch.acf.gov/docs/2025/state-plans/MD_Plan_2025.pdf#page=11", + # PDF pages 9, 10, 11. + "https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=9", + "https://regs.maryland.gov/us/md/exec/comar/07.03.21.07", + ) + documentation = ( + "Annual regular heating assistance, verified for state FY25 to FY27 (July " + "2024 to June 2027), which periods 2025 to 2027 read at January 1. Earlier " + "results are unverified backfilled estimates. No actual-bill cap applies. " + "Kerosene uses the oil row (labeled Oil/Kerosene from FY27) and a grid-tied " + "solar home uses the electricity row; heat-in-rent uses the building's known " + "fuel row, an inference because no separate renter table is published. Other " + "and unspecified fuels return zero as a coverage gap. Garrett County applies " + "the plan's 1.1 multiplier with half-up rounding; the published FY27 Garrett " + "table matches it in every cell but oil Level 4, which prints $1,210 where " + "1.1 times $980 is $1,078. An unknown county receives the statewide amount. " + "Means-tested VA eligibility remains unsupported. The $21 SNAP nominal " + "payment, cooling, EUSP, arrearage, crisis and equipment benefits are " + "excluded." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.dhs.meap.payment + # The floor keeps units outside Maryland (level 0) on a valid amount key. + level = max_(spm_unit("md_meap_level", period), 1) + fuel = spm_unit("heating_type", period) + types = fuel.possible_values + # A grid-tied solar home pays an electricity bill, the pairing + # heating_expense uses; manual 1.1.1 (page 6) lists solar subscriptions. + amount = select( + [ + (fuel == types.ELECTRICITY) | (fuel == types.SOLAR), + fuel == types.NATURAL_GAS, + (fuel == types.WOOD) | (fuel == types.COAL), + (fuel == types.FUEL_OIL) | (fuel == types.KEROSENE), + fuel == types.PROPANE, + ], + [ + p.amount.electricity[level], + p.amount.gas[level], + p.amount.wood_coal[level], + p.amount.oil[level], + p.amount.propane[level], + ], + # Other and unspecified fuels have no matrix row; the unspecified + # default is tracked in #9754. + default=0, + ) + county = spm_unit.household("county_str", period) + regional = np.isin(county, p.regional_counties) & (level != p.nominal_level) + # Half-up rounding and the flat nominal amount follow the FY27 Garrett + # table; FY25 and FY26 publish no Garrett dollar table. + return np.floor(amount * where(regional, p.garrett_multiplier, 1) + 0.5) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/md_meap_dwelling_type.py b/policyengine_us/variables/gov/states/md/dhs/meap/md_meap_dwelling_type.py new file mode 100644 index 00000000000..fe608267eaf --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/md_meap_dwelling_type.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class MDMEAPDwellingType(Enum): + STANDARD = "Standard residence" + SUB_METERED = "Submetered residence" + ASSISTED_LIVING = "Assisted living facility" + + +class md_meap_dwelling_type(Variable): + value_type = Enum + possible_values = MDMEAPDwellingType + default_value = MDMEAPDwellingType.STANDARD + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP dwelling arrangement" + reference = ( + "https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf", + "https://regs.maryland.gov/us/md/exec/comar/07.03.21.06#D(3)(k)", + ) + documentation = ( + "Submetered homes use the published Level 6 payment; assisted-living " + "applicants are ineligible under COMAR 07.03.21.06D(3)(k). Ordinary subsidized " + "homes use the existing housing-assistance inputs. If omitted, the model " + "assumes a standard residence." + ) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/payment/md_meap_level.py b/policyengine_us/variables/gov/states/md/dhs/meap/payment/md_meap_level.py new file mode 100644 index 00000000000..022e4a380c3 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/dhs/meap/payment/md_meap_level.py @@ -0,0 +1,42 @@ +from policyengine_us.model_api import * + + +class md_meap_level(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "Maryland MEAP heating payment level" + defined_for = StateCode.MD + reference = ( + "https://dhs.maryland.gov/documents/OHEP/Advisory%20Board/FY26-MEAP-Benefit-Matrix-2-1-1.pdf", + # PDF pages 62, 63. + "https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=62", + "https://liheapch.acf.gov/docs/2026/state-plans/MD_Plan_2026.pdf#page=9", + ) + documentation = ( + "Submetered and subsidized homes use Level 6. The over-200% categorical " + "nominal level takes precedence over these housing categories; this precedence " + "follows the manual's nominal-payment instruction. Existing assistance inputs " + "approximate the regulation's narrower subsidy definition." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.dhs.meap.payment + income = spm_unit("md_meap_countable_income", period) + fpg = spm_unit("md_meap_fpg", period) + # md_meap_fpg is zero outside Maryland; the substitute divisor avoids + # 0 / 0 on rows that defined_for masks afterwards. + ratio = income / where(fpg > 0, fpg, 1) + # Inclusive band tops resolve the gaps between integer percentage labels. + # The top bracket is Level 7, which nominal_level also names. + income_level = p.income_level.calc(ratio, right=True) + subsidized = spm_unit( + "receives_housing_assistance", period + ) | spm_unit.household("is_in_public_housing", period) + dwelling = spm_unit("md_meap_dwelling_type", period) + submetered = dwelling == dwelling.possible_values.SUB_METERED + return where( + (income_level != p.nominal_level) & (subsidized | submetered), + p.subsidized_level, + income_level, + )