diff --git a/changelog.d/ny-heap.added.md b/changelog.d/ny-heap.added.md new file mode 100644 index 00000000000..d4032b14018 --- /dev/null +++ b/changelog.d/ny-heap.added.md @@ -0,0 +1 @@ +Add New York HEAP regular heating assistance for FY2024 to FY2026. diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/fpg_rate.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/fpg_rate.yaml new file mode 100644 index 00000000000..35f8aa2b130 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/fpg_rate.yaml @@ -0,0 +1,12 @@ +description: New York uses this poverty guideline rate when it exceeds the state median income limit under the Home Energy Assistance Program. +values: + 2025-10-01: 1.5 +metadata: + unit: /1 + period: year + label: New York HEAP poverty guideline rate + reference: + - title: HEAP Manual (edition dated 7/1/2021), Chapter 8 D.9(c) + href: https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37 + - title: FY2026 LIHEAP State Plan, section 2.1 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/fpg_year_lag.yaml new file mode 100644 index 00000000000..64a5139b710 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/fpg_year_lag.yaml @@ -0,0 +1,15 @@ +description: New York uses the poverty guidelines from this many years before the model year under the Home Energy Assistance Program. +# Model period Y uses the FFY Y matrix, whose Tier I lines are 130% of the +# guidelines published in January of Y-1: floor(1.3 x 15,650 / 12) = 1,695 for +# one person in FY2026. The FY2025 and FY2024 lines reproduce the same way. +values: + 2025-10-01: 1 +metadata: + unit: year + period: year + label: New York HEAP poverty guideline year lag + reference: + - title: 2025-2026 HEAP monthly income guidelines + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx + - title: 2025 HHS poverty guidelines, 90 FR 5733, January 17, 2025 + href: https://www.govinfo.gov/content/pkg/FR-2025-01-17/pdf/2025-01377.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/smi_rate.yaml new file mode 100644 index 00000000000..41339fbb069 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/eligibility/smi_rate.yaml @@ -0,0 +1,10 @@ +description: New York limits noncategorical income using this share of state median income under the Home Energy Assistance Program. +values: + 2025-10-01: 0.6 +metadata: + unit: /1 + period: year + label: New York HEAP SMI rate + reference: + - title: FY2026 LIHEAP State Plan, regular heating assistance, PDF page 9 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/income/dependent_child_age.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/income/dependent_child_age.yaml new file mode 100644 index 00000000000..fe662a3a74e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/income/dependent_child_age.yaml @@ -0,0 +1,10 @@ +description: New York excludes earnings of dependent children below this age under the Home Energy Assistance Program. +values: + 2025-10-01: 18 +metadata: + unit: year + period: year + label: New York HEAP dependent child age + reference: + - title: HEAP Manual (edition dated 7/1/2021), Chapter 8 D.13(a)(4)-(5) + href: https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=39 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/income/sources/earned.yaml new file mode 100644 index 00000000000..afb25cdb697 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/income/sources/earned.yaml @@ -0,0 +1,16 @@ +description: New York uses these sources as earned income under the Home Energy Assistance Program. +# Existing net business inputs are used without a further expense deduction. +values: + 2025-10-01: + - employment_income + - self_employment_income + - sstb_self_employment_income + - farm_operations_income + - partnership_s_corp_income +metadata: + unit: list + period: year + label: New York HEAP earned sources + reference: + - title: HEAP Manual (edition dated 7/1/2021), Chapter 8 D.12 and D.14, PDF pages 37, 38, 42, 43 + href: https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/income/sources/unearned.yaml new file mode 100644 index 00000000000..95dc3e60e45 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/income/sources/unearned.yaml @@ -0,0 +1,37 @@ +description: New York uses these sources as unearned income under the Home Energy Assistance Program. +values: + 2025-10-01: + # Social Security and railroad benefits are counted in the formula, net of the + # Medicare Part B premium under D.12(a)(6) and (8). + - ssi + - unemployment_compensation + - strike_benefits + - workers_compensation + - disability_benefits + - veterans_benefits + # Survivor benefits other than Social Security survivor benefits: employer + # pension survivor annuities under D.12(a)(13) pensions and (14) payments from + # insurance and annuities; veterans' survivor benefits under D.12(a)(12). + - survivor_benefits + - pension_income + - retirement_distributions + - alimony_income + - child_support_received + - ordinary_dividend_income + - interest_income + - rental_income + # D.12(a)(27): income from rents. + - farm_rent_income + - estate_income + # D.12(a)(38): all other income not specifically excluded under D.13. Plan + # section 1.9 (page 7) leaves the "Other" box unchecked; the manual controls. + - miscellaneous_income +metadata: + unit: list + period: year + label: New York HEAP unearned sources + reference: + - title: HEAP Manual (edition dated 7/1/2021), Chapter 8 D.12-D.14, PDF pages 37, 38, 39, 40, 41, 42, 43 + href: https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37 + - title: FY2026 LIHEAP State Plan, section 1.9 countable income, PDF pages 6, 7 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/base.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/base.yaml new file mode 100644 index 00000000000..b62fba7222b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/base.yaml @@ -0,0 +1,39 @@ +description: New York provides this base annual direct heating payment by primary heating fuel under the Home Energy Assistance Program. +ELECTRICITY: + 2023-10-01: 400 +NATURAL_GAS: + 2023-10-01: 400 +FUEL_OIL: + 2023-10-01: 900 +KEROSENE: + 2023-10-01: 900 +PROPANE: + 2023-10-01: 900 +WOOD: + 2023-10-01: 635 +COAL: + 2023-10-01: 635 +# The matrix's "other fuels" row covers fuels outside the named utility and +# delivered-fuel groups; the model places solar there. +OTHER: + 2023-10-01: 635 +SOLAR: + 2023-10-01: 635 +# No matrix row: an unknown fuel pays nothing. See #9754 for the default fuel. +UNSPECIFIED: + 2023-10-01: 0 +NONE: + 2023-10-01: 0 +metadata: + unit: currency-USD + period: year + label: New York HEAP direct heating base payment + breakdown: + - heating_type + reference: + - title: 2023-2024 HEAP Direct Heating Regular Base Benefit Levels + href: https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 + - title: 2024-2025 HEAP Direct Heating Regular Base Benefit Levels + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/NY_BenefitMatrix_2025.docx + - title: 2025-2026 HEAP Direct Heating Regular Base Benefit Levels + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/elderly_age.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/elderly_age.yaml new file mode 100644 index 00000000000..cbf49be6dcd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/elderly_age.yaml @@ -0,0 +1,10 @@ +description: New York sets this age at or above which a member is vulnerable under the Home Energy Assistance Program. +values: + 2025-10-01: 60 +metadata: + unit: year + period: year + label: New York HEAP elderly age + reference: + - title: FY2026 LIHEAP State Plan, regular heating assistance, PDF page 9 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/nominal.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/nominal.yaml new file mode 100644 index 00000000000..c99e2bc48f0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/nominal.yaml @@ -0,0 +1,18 @@ +description: New York provides this regular payment to specified group residences and subsidized households with heat included in rent under the Home Energy Assistance Program. +values: + 2023-10-01: 21 +metadata: + unit: currency-USD + period: year + label: New York HEAP nominal regular payment + reference: + - title: 2023-2024 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 + - title: 2024-2025 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/NY_BenefitMatrix_2025.docx + - title: 2025-2026 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx + - title: HEAP Manual (edition dated 7/1/2021), Chapter 8 F.2(c) and F.3, PDF page 45 + href: https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=45 + - title: FY2026 LIHEAP State Plan, section 1.7b nominal payment, PDF page 6 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/tier_one.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/tier_one.yaml new file mode 100644 index 00000000000..8c343d9d9fd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/tier_one.yaml @@ -0,0 +1,14 @@ +description: New York provides this regular payment to Tier I households with heat included in unsubsidized rent under the Home Energy Assistance Program. +values: + 2023-10-01: 50 +metadata: + unit: currency-USD + period: year + label: New York HEAP Tier I heat-included payment + reference: + - title: 2023-2024 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 + - title: 2024-2025 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/NY_BenefitMatrix_2025.docx + - title: 2025-2026 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/tier_two.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/tier_two.yaml new file mode 100644 index 00000000000..2e1122dc6ae --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/heat_included/tier_two.yaml @@ -0,0 +1,14 @@ +description: New York provides this regular payment to Tier II households with heat included in unsubsidized rent under the Home Energy Assistance Program. +values: + 2023-10-01: 45 +metadata: + unit: currency-USD + period: year + label: New York HEAP Tier II heat-included payment + reference: + - title: 2023-2024 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 + - title: 2024-2025 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/NY_BenefitMatrix_2025.docx + - title: 2025-2026 HEAP Heat Included Regular Benefit Levels + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/tier_one_fpg_rate.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/tier_one_fpg_rate.yaml new file mode 100644 index 00000000000..6b4ce3c3113 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/tier_one_fpg_rate.yaml @@ -0,0 +1,10 @@ +description: New York limits Tier I to noncategorical households at or below this share of the poverty guideline under the Home Energy Assistance Program. +values: + 2025-10-01: 1.3 +metadata: + unit: /1 + period: year + label: New York HEAP Tier I poverty rate + reference: + - title: FY2026 LIHEAP State Plan, regular heating assistance, PDF page 10 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=10 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/tier_one_supplement.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/tier_one_supplement.yaml new file mode 100644 index 00000000000..7bb1eed0e9e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/tier_one_supplement.yaml @@ -0,0 +1,17 @@ +description: New York provides this Tier I supplement to direct heating payments under the Home Energy Assistance Program. +values: + 2022-10-01: 41 + 2024-10-01: 61 +metadata: + unit: currency-USD + period: year + label: New York HEAP Tier I supplement + reference: + - title: 2022-2023 HEAP Direct Heating Regular Base Benefit Levels, Tier I add-on + href: https://liheapch.acf.gov/docs/2023/benefits-matricies/NY_BenefitMatrix_2023.pdf#page=1 + - title: 2023-2024 HEAP Direct Heating Regular Base Benefit Levels, Tier I add-on + href: https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 + - title: 2024-2025 HEAP Direct Heating Regular Base Benefit Levels, Tier I add-on + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/NY_BenefitMatrix_2025.docx + - title: FY2026 LIHEAP State Plan, regular heating assistance, PDF page 10 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=10 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/vulnerable_supplement.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/vulnerable_supplement.yaml new file mode 100644 index 00000000000..f688a9f1acf --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/vulnerable_supplement.yaml @@ -0,0 +1,16 @@ +description: New York provides this supplement once per direct heating household with a qualified vulnerable member under the Home Energy Assistance Program. +values: + 2023-10-01: 35 +metadata: + unit: currency-USD + period: year + label: New York HEAP vulnerable supplement + reference: + - title: 2023-2024 HEAP Direct Heating Regular Base Benefit Levels, vulnerable add-on + href: https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 + - title: 2024-2025 HEAP Direct Heating Regular Base Benefit Levels, vulnerable add-on + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/NY_BenefitMatrix_2025.docx + - title: 2025-2026 HEAP Direct Heating Regular Base Benefit Levels, vulnerable add-on + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx + - title: FY2026 LIHEAP State Plan, regular heating assistance, PDF page 9 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9 diff --git a/policyengine_us/parameters/gov/states/ny/otda/heap/payment/young_child_age.yaml b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/young_child_age.yaml new file mode 100644 index 00000000000..9a8ec14793c --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/otda/heap/payment/young_child_age.yaml @@ -0,0 +1,10 @@ +description: New York sets this age below which a child is vulnerable under the Home Energy Assistance Program. +values: + 2025-10-01: 6 +metadata: + unit: year + period: year + label: New York HEAP young child age + reference: + - title: FY2026 LIHEAP State Plan, regular heating assistance, PDF page 9 + href: https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 35ed6f1d2a5..077b93d3a8d 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, MD, MS, NC, NE, TX + coverage: DC, Riverside County, MA, IL, IN, KS, KY, MD, MS, NC, NE, NY, TX state_implementations: - state: DC status: complete @@ -884,6 +884,14 @@ programs: parameter_prefix: gov.states.ne.dhhs.liheap verified_years: "2026" notes: FY2026 regular heating only, with the single-family and multifamily schedules and the earned-income disregard. Crisis, cooling and weatherization assistance are out of scope. + - state: NY + status: partial + name: New York HEAP + full_name: New York Home Energy Assistance Program + variable: ny_heap + parameter_prefix: gov.states.ny.otda.heap + verified_years: "2024-2026" + notes: FY2024-FY2026 regular heating only, with the fuel base amounts, the Tier I and vulnerable supplements and the heat-included levels. Crisis, cooling, HERR and clean-and-tune assistance are out of scope. - state: TX status: partial name: Texas CEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_categorically_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_categorically_eligible.yaml new file mode 100644 index 00000000000..45c3ab4359c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_categorically_eligible.yaml @@ -0,0 +1,234 @@ +# HEAP Manual, Chapter 8 D.10 and D.11 (PDF page 37): a household is +# categorically income eligible when a household member is an active recipient +# of recurring TA, SNAP or Code A SSI; D.4(a) (page 36) lists who is not a +# household member. https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37 +# FY2026 State Plan item 1.4a (page 5): one member's receipt qualifies the +# whole household. +# https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=5 +# 18 NYCRR 393.4(c)(1)(iii): SSI "as a couple or individual living alone (SSI +# Living Arrangement Code A)". +# https://www.law.cornell.edu/regulations/new-york/18-NYCRR-393.4 + +- name: Case 1, SNAP receipt confers categorical eligibility and no benefit receipt does not. + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY] + # $200 a month of SNAP for the first single adult; none for the second. + snap: [2_400, 0] + tanf: [0, 0] + ssi: [0, 0] + output: + # D.10(c) (page 37): the SNAP recipient's household qualifies; the other + # household is income tested under D.9 (page 37). + ny_heap_categorically_eligible: [true, false] + +- name: Case 2, a single SSI recipient in the federal own-household arrangement is Code A. + period: 2026 + input: + heating_type: NATURAL_GAS + state_code: NY + snap: 0 + tanf: 0 + ssi: 1_200 + ssi_federal_living_arrangement: + 2026-01: OWN_HOUSEHOLD + output: + # State Plan 1.4a (page 5) and D.10(c) (page 37): Code A SSI receipt + # qualifies. 18 NYCRR 393.4(c)(1)(iii) and the glossary (page 110) define + # Code A as an individual or couple living alone in the federal + # own-household arrangement; a recipient living alone satisfies both. + ny_heap_categorically_eligible: true + +- name: Case 3, a TANF entitlement that is not taken up does not confer categorical eligibility. + period: 2026 + input: + people: + person1: + age: 28 + ssi: 0 + person2: + age: 4 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + # Two-person New York City grant with no other income: $252 basic + # allowance + $22.50 home energy + $17 supplemental home energy + $283 + # shelter = $574.50 a month (18 NYCRR 352.1 to 352.3). + ny_tanf: 6_894 + takes_up_tanf_if_eligible: false + snap: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + # D.10(c) and D.11(a) (page 37) require active receipt of recurring TA; an + # unclaimed entitlement is not receipt. + ny_heap_categorically_eligible: false + +- name: Case 4, an excluded foster member or a nonqualified SSI recipient does not confer categorical eligibility. + period: 2026 + input: + state_code: [NY, NY] + heating_type: [NATURAL_GAS, NATURAL_GAS] + age: [40, 40] + ssi: [1_200, 1_200] + snap: [0, 0] + tanf: [0, 0] + is_citizen_or_legal_immigrant: [true, false] + is_in_foster_care: + 2026-01: [true, false] + ssi_federal_living_arrangement: + 2026-01: [OWN_HOUSEHOLD, OWN_HOUSEHOLD] + output: + # D.4(a)(3) and (7) (page 36): a foster member and a nonqualified + # noncitizen are not household members, and D.11(b) (page 37) requires the + # benefit recipient to be a HEAP household member. + ny_heap_categorically_eligible: [false, false] + +- name: Case 5, TANF receipt confers categorical eligibility. + period: 2026 + input: + people: + person1: + age: 28 + ssi: 0 + person2: + age: 4 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + # Two-person New York City grant with no other income: $252 basic + # allowance + $22.50 home energy + $17 supplemental home energy + $283 + # shelter = $574.50 a month (18 NYCRR 352.1 to 352.3). + tanf: 6_894 + snap: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + # D.10(c) (page 37) and State Plan 1.4a (page 5): receipt of federally + # funded Public Assistance by one member qualifies the household. + ny_heap_categorically_eligible: true + +- name: Case 6, a TANF entitlement that is taken up confers categorical eligibility. + period: 2026 + input: + people: + person1: + age: 28 + ssi: 0 + person2: + age: 4 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + # Same two-person New York City grant as Case 3, taken up. + ny_tanf: 6_894 + takes_up_tanf_if_eligible: true + snap: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + # D.10(c) (page 37): the family is an active recipient of recurring TA. + ny_heap_categorically_eligible: true + +- name: Case 7, an SSI recipient living with her daughter's family is not Code A, so the household is income tested. + period: 2026 + input: + people: + person1: + age: 72 + # Federal SSI of $994 a month. + ssi: 11_928 + ssi_federal_living_arrangement: + 2026-01: OWN_HOUSEHOLD + person2: + age: 45 + # Full-time wages of $4,000 a month. + employment_income: 48_000 + ssi: 0 + person3: + age: 47 + # Full-time wages of $3,000 a month. + employment_income: 36_000 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + gas_expense: 1_500 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2, person3] + state_code: NY + output: + # 393.4(c)(1)(iii) and the glossary (page 110): Code A means living alone, + # and this recipient lives with two other adults. + ny_heap_categorically_eligible: false + # 48,000 + 36,000 wages (D.12(a)(1), page 37) + 11,928 SSI (D.12(a)(7), + # page 38) = 95,928, which is 7,994 a month. + ny_heap_countable_income: 95_928 + # Three-person Tier II maximum 5,611 x 12 (2025-2026 HEAP Monthly Income + # Eligibility Guidelines); 7,994 a month exceeds it. + ny_heap_income_limit: 67_332 + ny_heap_eligible: false + ny_heap: 0 + +- name: Case 8, an SSI couple living alone is Code A. + period: 2026 + input: + people: + person1: + age: 68 + # The couple's federal SSI rate of $1,491 a month, split between them. + ssi: 8_946 + ssi_federal_living_arrangement: + 2026-01: OWN_HOUSEHOLD + person2: + age: 66 + ssi: 8_946 + ssi_federal_living_arrangement: + 2026-01: OWN_HOUSEHOLD + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_500 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + # 393.4(c)(1)(iii): SSI "as a couple ... living alone" qualifies. + ny_heap_categorically_eligible: true + +- name: Case 9, an SSI recipient living alone in another person's household is not in the federal Code A arrangement. + period: 2026 + input: + heating_type: NATURAL_GAS + state_code: NY + snap: 0 + tanf: 0 + ssi: 1_200 + ssi_federal_living_arrangement: + 2026-01: ANOTHER_PERSONS_HOUSEHOLD + output: + # The glossary (page 110) requires Code A for both state and federal SSI; + # a recipient in the federal another-person's-household arrangement is + # not federal Code A. + ny_heap_categorically_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_household_size.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_household_size.yaml new file mode 100644 index 00000000000..078b7e018c9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_household_size.yaml @@ -0,0 +1,105 @@ +# HEAP Manual, Chapter 8 D.4(a) (PDF page 36): foster members and federal +# living arrangement Code C SSI recipients are not household members; D.4(a)(7) +# still counts nonqualified members' income. +# https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=36 + +- name: Case 1, foster members and federal Code C SSI recipients do not affect the household award. + period: 2026 + input: + people: + person1: + age: 40 + # Full-time wages of $2,000 a month. + employment_income: 24_000 + ssi: 0 + person2: + age: 3 + is_in_foster_care: + 2026-01: true + social_security: 6_000 + ssi: 0 + person3: + age: 10 + ssi: 6_000 + ssi_federal_living_arrangement: + 2026-01: CHILD_IN_PARENTAL_HOUSEHOLD + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + gas_expense: 1_500 + tanf: 0 + snap: 0 + households: + household: + members: [person1, person2, person3] + state_code: NY + output: + # Only the adult counts: D.4(a)(3) excludes the foster child, and the model + # maps D.4(a)(5) to the federal child-in-parental-household arrangement + # with SSI receipt. + ny_heap_household_size: 1 + # The excluded members' income leaves with them: 24,000 of wages, which is + # 2,000 a month. + ny_heap_countable_income: 24_000 + # Chapter 9 B.3(b) (page 49): the only members under six or receiving SSI + # are excluded, and the adult is 40. + ny_heap_vulnerable: false + # No SNAP or TA, and the SSI recipient is not a household member (D.11(b), + # page 37). + ny_heap_categorically_eligible: false + # 2,000 a month exceeds the one-person Tier I maximum of 1,695 and is + # within the 3,473 limit (2025-2026 HEAP Monthly Income Eligibility + # Guidelines). + ny_heap_tier_one: false + # Utility base $400 with no add-ons (2025-2026 HEAP Direct Heating Regular + # Base Benefit Levels). + ny_heap: 400 + +- name: Case 2, the federal Code C arrangement without SSI receipt does not exclude a child. + period: 2026 + input: + state_code: NY + heating_type: NATURAL_GAS + age: 10 + ssi: 0 + receives_ssi: false + ssi_federal_living_arrangement: + 2026-01: CHILD_IN_PARENTAL_HOUSEHOLD + output: + # D.4(a)(5) (page 36) names SSI recipients, so a child in that arrangement + # who receives no SSI is counted. + ny_heap_household_size: 1 + # Chapter 9 B.3(b) (page 49): aged 10, so not under six, and no SSI receipt. + ny_heap_vulnerable: false + +- name: Case 3, reported SSI receipt in the federal Code C arrangement excludes a child. + period: 2026 + input: + people: + person1: + age: 40 + # Full-time wages of $2,000 a month. + employment_income: 24_000 + ssi: 0 + person2: + age: 10 + ssi: 0 + receives_ssi: true + ssi_federal_living_arrangement: + 2026-01: CHILD_IN_PARENTAL_HOUSEHOLD + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_500 + tanf: 0 + snap: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + # D.4(a)(5) (page 36): the child is an SSI recipient by reported receipt, + # so only the adult counts. + ny_heap_household_size: 1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_income_limit.yaml new file mode 100644 index 00000000000..d874a870cc5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/eligibility/ny_heap_income_limit.yaml @@ -0,0 +1,60 @@ +# 2025-2026 HEAP Monthly Income Eligibility Guidelines (Clearinghouse benefit +# matrix), Tier II maximum column, annualized (x 12). FY2026 State Plan section +# 2.1 (page 9) sets 60% of state median income for sizes 1 to 13 and 150% of +# the HHS poverty guideline for size 14; HEAP Manual Chapter 8 D.9(c) (page +# 37) uses the higher of the two. +# https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx +# https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9 +# https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37 + +- name: Case 1, odd household sizes one through thirteen published income limits. + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY, NY, NY, NY, NY, NY] + ny_heap_household_size: [1, 3, 5, 7, 9, 11, 13] + output: + # Odd sizes 1, 3, 5, 7, 9, 11 and 13 (the even Tier II maximums are not + # asserted; payment/ny_heap_tier_one.yaml tests the Tier I column at the + # even sizes). Published monthly Tier II maximums + # 3,473; 5,611; 7,749; 9,018; 9,419; 9,820; 10,221 (benefit matrix Tier II + # column; State Plan 2.1, page 9), each x 12. + ny_heap_income_limit: [41_676, 67_332, 92_988, 108_216, 113_028, 117_840, 122_652] + +- name: Case 2, size fourteen follows the plan poverty rate rather than the matrix increment. + period: 2026 + input: + heating_type: NATURAL_GAS + state_code: NY + ny_heap_household_size: 14 + output: + # State Plan 2.1 row 14 (page 9): 150% of the HHS poverty guideline. The + # 2025 guideline for 14 is 15,650 + 13 x 5,500 = 87,150; + # floor(1.5 x 87,150 / 12) = 10,893 a month, 130,716 a year. The matrix's + # 14+ row adds 687 to the size-13 maximum instead (10,908); the plan rule is + # encoded. + ny_heap_income_limit: 130_716 + +# 2024-2025 and 2023-2024 HEAP Monthly Income Eligibility Guidelines +# (Clearinghouse benefit matrices), Tier II maximum column, annualized. +# https://liheapch.acf.gov/docs/2025/benefits-matricies/NY_BenefitMatrix_2025.docx +# https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 +- name: Case 3, FY2025 published income limits at sizes one, four and thirteen. + period: 2025 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY, NY] + ny_heap_household_size: [1, 4, 13] + output: + # 2024-2025 Tier II maximums 3,322; 6,390; 9,952, each x 12. + ny_heap_income_limit: [39_864, 76_680, 119_424] + +- name: Case 4, FY2024 published income limits at sizes one, four and thirteen. + period: 2024 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY, NY] + ny_heap_household_size: [1, 4, 13] + output: + # 2023-2024 Tier II maximums 3,035; 5,838; 9,532, each x 12. + ny_heap_income_limit: [36_420, 70_056, 114_384] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_countable_earned_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_countable_earned_income.yaml new file mode 100644 index 00000000000..1e82efa3530 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_countable_earned_income.yaml @@ -0,0 +1,61 @@ +# HEAP Manual, Chapter 8 D.12(a)(1) and (5) (PDF page 37) count gross wages +# and net profit from self-employment; D.13(a)(4) and (5) (page 39) exclude +# the earned income of full-time dependent students aged 18 and older and of +# dependent minors under 18. +# https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37 + +- name: Case 1, dependent minors and full-time dependent students have exempt earnings. + period: 2026 + input: + people: + person1: + age: 17 + is_tax_unit_dependent: true + is_full_time_student: false + employment_income: 12_000 + self_employment_income: 1_000 + sstb_self_employment_income: 500 + farm_operations_income: 600 + partnership_s_corp_income: 700 + person2: + age: 18 + is_tax_unit_dependent: true + is_full_time_student: true + employment_income: 12_000 + self_employment_income: 1_000 + sstb_self_employment_income: 500 + farm_operations_income: 600 + partnership_s_corp_income: 700 + person3: + age: 45 + is_tax_unit_dependent: false + is_full_time_student: true + employment_income: 12_000 + self_employment_income: 1_000 + sstb_self_employment_income: 500 + farm_operations_income: 600 + partnership_s_corp_income: 700 + person4: + age: 47 + is_tax_unit_dependent: false + is_full_time_student: false + employment_income: 12_000 + self_employment_income: -1_000 + sstb_self_employment_income: 500 + farm_operations_income: 600 + partnership_s_corp_income: 700 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2, person3, person4] + state_code: NY + output: + # D.13(a)(5): the 17-year-old dependent's earnings are excluded; D.13(a)(4): + # so are the 18-year-old full-time dependent student's. The adult student + # is not a dependent, so 12,000 + 1,000 + 500 + 600 + 700 = 14,800 counts. + # A self-employment loss is not net profit under D.12(a)(5), so the last + # adult counts 12,000 + 500 + 600 + 700 = 13,800. + ny_heap_countable_earned_income: [0, 0, 14_800, 13_800] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_countable_income.yaml new file mode 100644 index 00000000000..1b492a2850f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_countable_income.yaml @@ -0,0 +1,156 @@ +# HEAP Manual, Chapter 8 D.12 to D.14 (PDF pages 37 to 43): countable and +# excluded income; D.14(c) (page 43) rounds final calculations down to the +# nearest dollar. https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37 +# FY2026 State Plan item 1.9 (page 6) lists the counted income forms and leaves +# the TANF box unchecked. +# https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=6 + +- name: Case 1, Social Security counts net of the Medicare Part B premium and monthly household income rounds down. + period: 2026 + input: + heating_type: NATURAL_GAS + state_code: NY + ny_heap_countable_earned_income: 12_001 + social_security: 12_000 + # D.12(a)(6) (page 38) counts Social Security after the Medicare premium, + # so the $100 a month of Part B premium reduces the total. + medicare_part_b_premium: 1_200 + railroad_benefits: 600 + pension_income: 240 + retirement_distributions: 360 + interest_income: 120 + ordinary_dividend_income: 240 + rental_income: 360 + alimony_income: 480 + child_support_received: 600 + unemployment_compensation: 720 + strike_benefits: 120 + workers_compensation: 240 + disability_benefits: 360 + veterans_benefits: 480 + estate_income: 120 + ssi: 0 + output: + # 12,001 earnings + 12,600 Social Security and railroad benefits less the + # 1,200 Part B premium (D.12(a)(6) and (8), page 38) + 4,440 from the other + # counted sources in D.12(a)(10) to (28) (pages 38 to 39) = 27,841. D.14(c) + # (page 43): floor(27,841 / 12) = 2,320 a month, annualized 27,840. + ny_heap_countable_income: 27_840 + +- name: Case 2, TANF cash assistance is not counted as income. + period: 2026 + input: + people: + person1: + age: 28 + ssi: 0 + person2: + age: 4 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + # Two-person New York City grant with no other income: $252 basic + # allowance + $22.50 home energy + $17 supplemental home energy + $283 + # shelter = $574.50 a month (18 NYCRR 352.1 to 352.3). + tanf: 6_894 + snap: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + # State Plan item 1.9 (page 6) leaves the TANF box unchecked, and Chapter 8 + # D.11(c)(1) (page 37) counts a TA grant only for a minor child budgeted as + # a roomer, so the grant adds nothing to the household's countable income. + ny_heap_countable_income: 0 + # Chapter 8 D.10(c) (page 37): the recurring TA recipient household is + # categorically income eligible instead. + ny_heap_categorically_eligible: true + +- name: Case 3, survivor benefits, farm rent and miscellaneous income are counted. + period: 2026 + input: + people: + person1: + age: 61 + # Part-time wages of $1,000 a month. + employment_income: 12_000 + # An $800 monthly survivor annuity from a late spouse's employer + # pension, $500 of farm cropland rent and $100 of other regular income. + survivor_benefits: 9_600 + farm_rent_income: 6_000 + miscellaneous_income: 1_200 + ssi: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: FUEL_OIL + # About 700 gallons of heating oil at $4.00 a gallon. + fuel_oil_expense: 2_800 + snap: 0 + tanf: 0 + households: + household: + members: [person1] + state_code: NY + output: + # D.12(a)(1) wages (page 37); D.12(a)(13) pensions and (14) payments from + # insurance and annuities for the employer pension survivor annuity (page + # 38); (27) income from rents and (38) all other income not excluded (pages + # 38 to 39): 12,000 + 9,600 + 6,000 + 1,200 = 28,800, which is 2,400 a month. + ny_heap_countable_income: 28_800 + # 2,400 a month exceeds the one-person Tier I maximum of 1,695 in the + # 2025-2026 HEAP Monthly Income Eligibility Guidelines; the wages alone + # would have been Tier I. + ny_heap_tier_one: false + # Oil base $900 + $35 for a member aged 60 or older (2025-2026 HEAP Direct + # Heating Regular Base Benefit Levels, vulnerable add-on column) = $935. + ny_heap: 935 + +- name: Case 4, a rental loss does not offset wages. + period: 2026 + input: + state_code: NY + heating_type: NATURAL_GAS + gas_expense: 1_500 + age: 40 + # Full-time wages of $3,600 a month. + ny_heap_countable_earned_income: 43_200 + rental_income: -6_000 + ssi: 0 + snap: 0 + tanf: 0 + output: + # D.14(b)(7) (page 41) converts negative income to zero and lists net loss + # as a deduction that is not allowed, so the loss counts as 0 and the + # wages count in full: 3,600 a month. + ny_heap_countable_income: 43_200 + # 3,600 a month exceeds the one-person Tier II maximum of 3,473. + ny_heap: 0 + +- name: Case 5, the Medicare Part B premium brings a retiree under the income limit. + period: 2026 + input: + state_code: NY + heating_type: NATURAL_GAS + gas_expense: 1_500 + age: 70 + # Social Security retirement of $3,600 a month. + social_security: 43_200 + # The standard 2026 Part B premium of $202.90 a month, not covered by a + # Medicare Savings Program at this income. + medicare_part_b_premium: 2_434.8 + ssi: 0 + snap: 0 + tanf: 0 + output: + # D.14(b)(4) (page 41): the benefit after the Part B premium is counted, + # 43,200 - 2,434.80 = 40,765.20; D.14(c): floor(40,765.20 / 12) = 3,397 a + # month, annualized 40,764. + ny_heap_countable_income: 40_764 + # 3,397 a month is within the one-person Tier II maximum of 3,473 and + # above the Tier I maximum of 1,695: Utility 400 + 35 for a member aged 60 + # or older (Chapter 9 B.3(b)(2), page 49) = 435. + ny_heap: 435 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_fpg.yaml new file mode 100644 index 00000000000..4ac77d09d12 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/income/ny_heap_fpg.yaml @@ -0,0 +1,15 @@ +# The 2025-2026 HEAP Monthly Income Eligibility Guidelines (Clearinghouse +# benefit matrix) reproduce from the poverty guideline of the year before the +# program year, so the model lags the guideline by one year. +# https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx + +- name: Case 1, backfilled estimates use the guideline one year before the requested period. + period: 2022 + input: + heating_type: NATURAL_GAS + state_code: NY + ny_heap_household_size: 2 + output: + # 2021 HHS poverty guideline for two: 12,880 + 4,540 = 17,420. This checks + # the lag mechanics, not verified historical New York policy coverage. + ny_heap_fpg: 17_420 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/integration.yaml new file mode 100644 index 00000000000..d89f0c3b7e0 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/integration.yaml @@ -0,0 +1,323 @@ +# 2025-2026 HEAP benefit levels and monthly income guidelines (Clearinghouse +# benefit matrix): Utility $400; Oil, Kerosene, and Propane $900; Wood, +# Pellets, Coal, other fuels $635; +$35 vulnerable member; +$61 Tier I; heat +# included $50 (Tier I), $45 (Tier II), $21 (Heat and Eat). Monthly Tier I +# maximums 1,695 / 2,291 / 2,887 and Tier II maximums 3,473 / 4,542 / 5,611 +# for one to three people. +# https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx +# FY2026 State Plan: categorical eligibility (1.4a, page 5), income limits +# (2.1, page 9), add-ons and the 130% Tier I line (pages 9 to 10). +# https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=5 +# HEAP Manual, Chapter 8 (PDF pages 34 to 47) and Chapter 9 B.3 (page 49). +# https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=34 +# The 2025 poverty guideline (15,650 + 5,500 per additional person) drives the +# Tier I line; snap, tanf and ssi are reported receipts so that each case rests +# on the HEAP rules alone. + +- name: Case 1, a nonqualified adult's income counts in full while the citizen child determines size and vulnerability. + period: 2026 + input: + people: + person1: + age: 40 + # Full-time wages of $2,000 a month. + employment_income: 24_000 + immigration_status: UNDOCUMENTED + person2: + age: 5 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_500 + tanf: 0 + snap: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + # Chapter 8 E.9(b) (page 45): size counts citizens and qualified + # noncitizens only. + ny_heap_household_size: 1 + # D.4(a)(7) (page 36) and E.4 (page 44): the nonqualified member's income + # is counted: 24,000. + ny_heap_countable_income: 24_000 + # One-person Tier II maximum 3,473 x 12. + ny_heap_income_limit: 41_676 + # 2,000 a month exceeds the one-person Tier I maximum of 1,695. + ny_heap_tier_one: false + # Chapter 9 B.3(b)(1) (page 49): the citizen child is under six. + ny_heap_vulnerable: true + ny_heap_eligible: true + # Utility 400 + 35 = 435. + ny_heap: 435 + +- name: Case 2, no qualified household member means no benefit. + period: 2026 + input: + state_code: NY + immigration_status: UNDOCUMENTED + age: 40 + # Wages of $2,500 a month, within the one-person limit, so only the member + # rule denies the benefit. + employment_income: 30_000 + ssi: 0 + snap: 0 + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_500 + output: + ny_heap_household_size: 0 + # Chapter 8 E.8(a) (page 45): no benefit is issued when all household + # members are nonqualified. + ny_heap_eligible: false + ny_heap: 0 + +- name: Case 3, only a nonqualified elderly member does not confer the vulnerable supplement. + period: 2026 + input: + people: + person1: + age: 40 + # Full-time wages of $2,000 a month. + employment_income: 24_000 + ssi: 0 + person2: + age: 70 + immigration_status: UNDOCUMENTED + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_500 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + # E.9(b) (page 45): only the citizen counts. + ny_heap_household_size: 1 + ny_heap_countable_income: 24_000 + ny_heap_categorically_eligible: false + # 2,000 a month exceeds the one-person Tier I maximum of 1,695. + ny_heap_tier_one: false + # E.9(c) (page 45): "If the only vulnerable individual is a non-qualified + # alien, the add-on for vulnerability is not included". + ny_heap_vulnerable: false + ny_heap_eligible: true + # Utility base $400. + ny_heap: 400 + +- name: Case 4, a SNAP recipient's household above the income limit is categorically eligible and paid the Tier I supplement. + period: 2026 + input: + people: + person1: + age: 44 + # Full-time wages of $4,800 a month. + employment_income: 57_600 + ssi: 0 + person2: + age: 39 + # Part-time wages of $1,200 a month. + employment_income: 14_400 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_600 + # The brothers buy and prepare food separately; the second receives + # about $75 a month of SNAP on his own case (reported receipt). + snap: 900 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + ny_heap_household_size: 2 + ny_heap_countable_earned_income: [57_600, 14_400] + # 57,600 + 14,400 = 72,000, which is 6,000 a month. + ny_heap_countable_income: 72_000 + # 2025 guideline for two: 15,650 + 5,500. + ny_heap_fpg: 21_150 + # Two-person Tier II maximum 4,542 x 12; 6,000 a month exceeds it. + ny_heap_income_limit: 54_504 + # Chapter 8 D.10(c) (page 37) and State Plan 1.4a (page 5): one member's + # SNAP receipt qualifies the household. + ny_heap_categorically_eligible: true + # State Plan page 10: the $61 add-on also applies to CE households. + ny_heap_tier_one: true + # Aged 44 and 39, with no child or qualifying disability. + ny_heap_vulnerable: false + ny_heap_eligible: true + # Utility 400 + 61 = 461. + ny_heap: 461 + +- name: Case 5, a household above the income limit without categorical eligibility is denied. + period: 2026 + input: + people: + person1: + age: 38 + # Full-time wages of $4,000 a month. + employment_income: 48_000 + ssi: 0 + person2: + age: 36 + # Full-time wages of $2,500 a month. + employment_income: 30_000 + ssi: 0 + person3: + age: 7 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + gas_expense: 1_600 + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2, person3] + state_code: NY + output: + ny_heap_household_size: 3 + # 48,000 + 30,000 = 78,000, which is 6,500 a month. + ny_heap_countable_income: 78_000 + # 2025 guideline for three: 15,650 + 2 x 5,500. + ny_heap_fpg: 26_650 + # Three-person Tier II maximum 5,611 x 12. + ny_heap_income_limit: 67_332 + ny_heap_categorically_eligible: false + # 6,500 a month exceeds the three-person Tier I maximum of 2,887. + ny_heap_tier_one: false + ny_heap_eligible: false + # Chapter 8 D.9(d) (page 37): denied for excess income. + ny_heap: 0 + +- name: Case 6, an older oil heater in Tier I receives both supplements. + period: 2026 + input: + people: + person1: + age: 63 + # Early Social Security retirement of $1,400 a month. + social_security_retirement: 16_800 + ssi: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: FUEL_OIL + # About 750 gallons of heating oil at $4.00 a gallon. + fuel_oil_expense: 3_000 + snap: 0 + tanf: 0 + households: + household: + members: [person1] + state_code: NY + output: + ny_heap_household_size: 1 + # Chapter 8 D.12(a)(6) (page 38): Social Security, 16,800 (1,400 a month; + # no Medicare premium before age 65). + ny_heap_countable_income: 16_800 + # 2025 guideline for one. + ny_heap_fpg: 15_650 + # One-person Tier II maximum 3,473 x 12. + ny_heap_income_limit: 41_676 + ny_heap_categorically_eligible: false + # 1,400 a month is within the one-person Tier I maximum of 1,695 + # (floor(1.3 x 15,650 / 12)). + ny_heap_tier_one: true + # Chapter 9 B.3(b)(2) (page 49): aged 60 or older. + ny_heap_vulnerable: true + ny_heap_eligible: true + # Oil, Kerosene, and Propane with both add-ons: 900 + 61 + 35 = 996, the + # plan's maximum benefit (page 10). + ny_heap: 996 + +- name: Case 7, a renter with heat included in rent receives the Tier I heat-included amount. + period: 2026 + input: + people: + person1: + age: 31 + # $17.00 an hour (the 2026 New York City minimum wage) for 30 hours a + # week: 2,210 a month. + employment_income: 26_520 + ssi: 0 + person2: + age: 8 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + # The building's boiler burns natural gas and the landlord pays for it. + heating_type: NATURAL_GAS + heat_expense_included_in_rent: true + snap: 0 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + ny_heap_household_size: 2 + ny_heap_countable_income: 26_520 + # Two-person Tier II maximum 4,542 x 12. + ny_heap_income_limit: 54_504 + ny_heap_categorically_eligible: false + # 2,210 a month is within the two-person Tier I maximum of 2,291. + ny_heap_tier_one: true + # No bill of its own: heat is paid indirectly through rent. + has_heating_expense: false + # Chapter 8 F.1 (page 45): undesignated payments for heat in rent are an + # eligible living arrangement. + ny_heap_eligible: true + # Heat Included Regular Benefit Levels, Tier I: $50. + ny_heap: 50 + +- name: Case 8, a public housing tenant with heat included receives the nominal payment. + period: 2026 + input: + people: + person1: + age: 58 + # Wages of $1,800 a month. + employment_income: 21_600 + ssi: 0 + spm_units: + spm_unit: + members: [person1] + # The tenant does not know the building's fuel; heat is in the rent. + heating_type: UNSPECIFIED + heat_expense_included_in_rent: true + snap: 0 + tanf: 0 + households: + household: + members: [person1] + state_code: NY + is_in_public_housing: true + output: + ny_heap_household_size: 1 + ny_heap_countable_income: 21_600 + ny_heap_categorically_eligible: false + # 1,800 a month exceeds the one-person Tier I maximum of 1,695 and is + # within the 3,473 limit. + ny_heap_tier_one: false + # Aged 58, so not yet 60 (Chapter 9 B.3(b)(2), page 49). + ny_heap_vulnerable: false + ny_heap_eligible: true + # Government subsidized housing with heat included in the rent: $21 + # (Chapter 8 F.2(c) and F.3(a), pages 45 to 46; Heat and Eat Benefit in the + # matrix) instead of the Tier II heat-included $45. + ny_heap: 21 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/ny_heap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/ny_heap.yaml new file mode 100644 index 00000000000..283a0d82302 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/ny_heap.yaml @@ -0,0 +1,332 @@ +# 2025-2026 HEAP Direct Heating Regular Base Benefit Levels and Heat Included +# Regular Benefit Levels (Clearinghouse benefit matrix): Utility $400; Oil, +# Kerosene, and Propane $900; Wood, Pellets, Coal, other fuels $635; +$35 for a +# vulnerable member; +$61 for Tier I; heat included $50 (Tier I), $45 (Tier II) +# and $21 (Heat and Eat). Tier I is income at or below 130% of the poverty +# guideline or categorical eligibility (FY2026 State Plan, page 10). +# https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx +# https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=10 +# Living arrangements: HEAP Manual, Chapter 8 F (PDF pages 45 to 47). +# https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=45 + +- name: Case 1, every fuel with the Tier I supplement. + period: 2026 + input: + state_code: [NY, NY, NY, NY, NY, NY, NY, NY, NY, NY, NY] + ny_heap_countable_income: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ny_heap_categorically_eligible: [false, false, false, false, false, false, false, false, false, false, false] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + heating_type: [ELECTRICITY, NATURAL_GAS, FUEL_OIL, KEROSENE, PROPANE, WOOD, COAL, OTHER, SOLAR, UNSPECIFIED, NONE] + # Each household sends its primary fuel's annual bill; an unspecified fuel + # and no heating have no fuel bill to send. + pre_subsidy_electricity_expense: [2_400, 0, 0, 0, 0, 0, 0, 0, 900, 0, 0] + gas_expense: [0, 1_500, 0, 0, 0, 0, 0, 0, 0, 0, 0] + fuel_oil_expense: [0, 0, 2_800, 2_800, 0, 0, 0, 0, 0, 0, 0] + bottled_gas_expense: [0, 0, 0, 0, 2_600, 0, 0, 0, 0, 0, 0] + wood_expense: [0, 0, 0, 0, 0, 1_200, 0, 0, 0, 0, 0] + coal_expense: [0, 0, 0, 0, 0, 0, 1_200, 0, 0, 0, 0] + other_heating_fuel_expense: [0, 0, 0, 0, 0, 0, 0, 1_300, 0, 0, 0] + output: + # Zero income is Tier I. Tier I add-on column: Utility 400 + 61 = 461; + # Oil, Kerosene, and Propane 900 + 61 = 961; Wood, Pellets, Coal, other + # fuels 635 + 61 = 696 (the model places solar in the other-fuels row). + # Without a fuel bill the last two households have no responsibility for + # heating costs (Chapter 8 F.4(g), page 46). + ny_heap: [461, 461, 961, 961, 961, 696, 696, 696, 696, 0, 0] + +- name: Case 2, age vulnerability boundary at sixty, Tier I and Tier II. + period: 2026 + input: + state_code: [NY, NY, NY, NY] + ny_heap_countable_income: [0, 0, 24_000, 24_000] + ny_heap_categorically_eligible: [false, false, false, false] + age: [59, 60, 40, 40] + heating_type: [FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL] + # About 700 gallons of heating oil at $4.00 a gallon. + fuel_oil_expense: [2_800, 2_800, 2_800, 2_800] + social_security_disability: [0, 0, 0, 1_200] + output: + # Chapter 9 B.3(b)(2) (page 49): aged 60 or older. Zero income is Tier I: + # 900 + 61 = 961 at 59 and 900 + 61 + 35 = 996 at 60. 2,000 a month is + # above the one-person Tier I maximum of 1,695: 900 alone, and 900 + 35 = + # 935 with Social Security disability receipt (B.3(b)(3)). + ny_heap: [961, 996, 900, 935] + +- name: Case 3, heat included in rent by tier and housing assistance. + period: 2026 + input: + state_code: [NY, NY, NY, NY] + ny_heap_countable_income: [0, 24_000, 0, 24_000] + ny_heap_categorically_eligible: [false, false, false, false] + age: [40, 40, 40, 40] + heat_expense_included_in_rent: [true, true, true, true] + heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] + receives_housing_assistance: [false, false, true, true] + output: + # Heat Included Regular Benefit Levels: Tier I $50 and Tier II $45 (2,000 a + # month is above the one-person Tier I maximum of 1,695). Tenants of + # subsidized housing with heat included receive the $21 nominal benefit in + # either tier (Chapter 8 F.2(c) and F.3(a), pages 45 to 46). + ny_heap: [50, 45, 21, 21] + +- name: Case 4, subsidized direct heaters receive ordinary fuel payments. + period: 2026 + input: + state_code: NY + ny_heap_countable_income: 0 + ny_heap_categorically_eligible: false + age: 40 + heating_type: NATURAL_GAS + gas_expense: 1_500 + receives_housing_assistance: true + output: + # F.3(a) (page 46) limits the $21 to subsidized housing with heat included + # in the rent; a subsidized tenant who pays the gas utility directly + # receives Utility 400 + 61 (Tier I) = 461. + ny_heap: 461 + +- name: Case 5, income eligibility includes the published limit. + period: 2026 + input: + state_code: [NY, NY] + # The one-person monthly maximum 3,473 x 12, and one more monthly dollar. + ny_heap_countable_income: [41_676, 41_688] + ny_heap_categorically_eligible: [false, false] + age: [40, 40] + heating_type: [ELECTRICITY, ELECTRICITY] + pre_subsidy_electricity_expense: [2_400, 2_400] + output: + # Chapter 8 D.9(a) (page 37): income "at or below the maximum" is eligible, + # so 3,473 a month receives the Utility base $400 (Tier II, no add-ons), + # and 3,474 a month is denied for excess income under D.9(d). + ny_heap: [400, 0] + +- name: Case 6, the regular benefit is not capped at the current heating bill. + period: 2026 + input: + state_code: NY + ny_heap_countable_income: 0 + ny_heap_categorically_eligible: false + age: 40 + heating_type: FUEL_OIL + # One 150-gallon delivery at about $4.00 a gallon. + fuel_oil_expense: 600 + output: + # The benefit matrix pays a flat amount by fuel group: Oil 900 + 61 (Tier I) + # = 961 regardless of the bill. + ny_heap: 961 + +- name: Case 7, households with no heat responsibility receive zero. + period: 2026 + input: + state_code: NY + ny_heap_countable_income: 0 + ny_heap_categorically_eligible: false + age: 40 + heating_type: NATURAL_GAS + # Gas heat, but the household pays no gas bill and heat is not in its rent. + gas_expense: 0 + output: + # Chapter 8 F.4(g) (page 46): households with no responsibility for heating + # costs that make no undesignated payments for heat in rent are ineligible. + ny_heap: 0 + +- name: Case 8, other states receive no New York payment. + period: 2026 + input: + state_code: NJ + ny_heap_countable_income: 0 + ny_heap_categorically_eligible: false + age: 40 + heating_type: NATURAL_GAS + gas_expense: 1_500 + output: + # Chapter 8 C.1 (page 34): the applicant must be a New York State resident. + ny_heap: 0 + +- name: Case 9, published group and ineligible residence categories. + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY] + ny_heap_countable_income: [0, 0] + ny_heap_categorically_eligible: [false, false] + age: [40, 40] + ny_heap_dwelling_type: [ELIGIBLE_GROUP_RESIDENCE, INELIGIBLE_RESIDENCE] + # The group residence needs no bill of its own; the ineligible residence + # pays a gas bill and is still denied. + gas_expense: [0, 1_500] + output: + # Chapter 8 F.3 (pages 45 to 46): the listed group residences receive a + # Regular benefit of $21; F.4 (pages 46 to 47): the listed arrangements are + # not eligible even when all other criteria are met. + ny_heap: [21, 0] + +- name: Case 10, a child under six makes the household vulnerable. + period: 2026 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: FUEL_OIL + # About 700 gallons of heating oil at $4.00 a gallon. + fuel_oil_expense: 2_800 + # Parent's wages of $2,000 a month. + ny_heap_countable_income: 24_000 + ny_heap_categorically_eligible: false + households: + household: + members: [person1, person2] + state_code: NY + output: + # 2,000 a month is within the two-person Tier I maximum of 2,291, and + # Chapter 9 B.3(b)(1) (page 49) makes a child under six vulnerable: + # 900 + 61 + 35 = 996. + ny_heap: 996 + +- name: Case 11, a child aged six is not a vulnerable member. + period: 2026 + input: + people: + person1: + age: 30 + person2: + age: 6 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: FUEL_OIL + # About 700 gallons of heating oil at $4.00 a gallon. + fuel_oil_expense: 2_800 + # Parent's wages of $2,000 a month. + ny_heap_countable_income: 24_000 + ny_heap_categorically_eligible: false + households: + household: + members: [person1, person2] + state_code: NY + output: + # Tier I (2,000 a month is within 2,291 for two) with no vulnerable + # member, since B.3(b)(1) (page 49) requires "under age six": 900 + 61 = 961. + ny_heap: 961 + +- name: Case 12, an unspecified fuel pays nothing even when a heating cost is reported directly. + period: 2026 + input: + state_code: NY + ny_heap_countable_income: 0 + ny_heap_categorically_eligible: false + has_heating_expense: true + age: 40 + heating_type: UNSPECIFIED + output: + # The benefit matrix pays by fuel group; a household whose fuel is unknown + # cannot be placed in a row, so no direct heating payment is made. This is + # a coverage gap: the UNSPECIFIED default is tracked in issue 9754. + ny_heap: 0 + +- name: Case 13, a SNAP recipient's household above the income limit is paid with the Tier I supplement. + period: 2026 + input: + people: + person1: + age: 46 + # Full-time wages of $5,200 a month. + employment_income: 62_400 + ssi: 0 + person2: + age: 63 + # Early Social Security retirement of $1,200 a month. + social_security_retirement: 14_400 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: WOOD + # About four and a half cords of firewood at $310 a cord. + wood_expense: 1_400 + # The parent buys and prepares food separately and receives the $24 + # minimum monthly SNAP allotment on her own case (reported receipt). + snap: 288 + tanf: 0 + households: + household: + members: [person1, person2] + state_code: NY + output: + ny_heap_household_size: 2 + # 62,400 wages + 14,400 Social Security (Chapter 8 D.12(a)(1) and (6), + # pages 37 to 38) = 76,800, which is 6,400 a month. + ny_heap_countable_income: 76_800 + # Two-person Tier II maximum 4,542 x 12 (2025-2026 HEAP Monthly Income + # Eligibility Guidelines); 6,400 a month exceeds it. + ny_heap_income_limit: 54_504 + # D.10(c) (page 37) and State Plan 1.4a (page 5): one member's SNAP receipt + # qualifies the household. + ny_heap_categorically_eligible: true + ny_heap_eligible: true + # State Plan page 10: the $61 add-on also applies to CE households. + ny_heap_tier_one: true + # Aged 63: Chapter 9 B.3(b)(2) (page 49). + ny_heap_vulnerable: true + # Wood, Pellets, Coal, other fuels with both add-ons: 635 + 61 + 35 = 731. + ny_heap: 731 + +- name: Case 14, public housing tenants receive the nominal payment only when heat is included in rent. + period: 2026 + input: + state_code: [NY, NY] + # Wages of $1,500 a month. + ny_heap_countable_income: [18_000, 18_000] + ny_heap_categorically_eligible: [false, false] + age: [40, 40] + is_in_public_housing: [true, true] + heat_expense_included_in_rent: [true, false] + heating_type: [UNSPECIFIED, NATURAL_GAS] + gas_expense: [0, 1_500] + output: + # 1,500 a month is Tier I (one-person maximum 1,695). Government subsidized + # housing with heat included in the rent receives $21 (Chapter 8 F.3(a), + # page 46) instead of the Tier I heat-included $50; a public housing tenant + # who pays the gas utility directly receives Utility 400 + 61 = 461. + ny_heap: [21, 461] + +- name: Case 15, a vulnerable member adds nothing to the heat-included payments. + period: 2026 + input: + state_code: [NY, NY] + ny_heap_countable_income: [0, 24_000] + ny_heap_categorically_eligible: [false, false] + age: [65, 65] + heat_expense_included_in_rent: [true, true] + heating_type: [UNSPECIFIED, UNSPECIFIED] + output: + # State Plan page 9: the $35 is added "to their base Regular heater + # benefit", so a 65-year-old with heat included in rent receives the Heat + # Included levels alone: Tier I $50 and Tier II $45 (2,000 a month is + # above the one-person Tier I maximum of 1,695). + ny_heap: [50, 45] + +# 2023-2024 HEAP Direct Heating Regular Base Benefit Levels (Clearinghouse +# benefit matrix): the same base amounts with a $41 Tier I add-on. +# https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 +- name: Case 16, the FY2024 Tier I add-on was $41. + period: 2024 + input: + state_code: [NY, NY] + ny_heap_countable_income: [0, 0] + ny_heap_categorically_eligible: [false, false] + age: [40, 40] + heating_type: [NATURAL_GAS, FUEL_OIL] + gas_expense: [1_500, 0] + # About 700 gallons of heating oil at $4.00 a gallon. + fuel_oil_expense: [0, 2_800] + output: + # 2023-2024 matrix, Tier I add-on column: Utility 400 + 41 = 441; Oil, + # Kerosene, and Propane 900 + 41 = 941. + ny_heap: [441, 941] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/payment/ny_heap_tier_one.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/payment/ny_heap_tier_one.yaml new file mode 100644 index 00000000000..715601aff23 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/payment/ny_heap_tier_one.yaml @@ -0,0 +1,80 @@ +# 2025-2026 HEAP Monthly Income Eligibility Guidelines (Clearinghouse benefit +# matrix), Tier I column: 0 to the listed maximum, which is 130% of the 2025 +# poverty guideline rounded down to the month (FY2026 State Plan, page 10: +# "at or below 130% of the Federal Poverty Level"). +# https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx +# https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=10 + +- name: Case 1, even household size published Tier I maximums are inclusive. + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY, NY, NY, NY, NY, NY, NY, NY, NY, NY, NY] + ny_heap_household_size: [2, 4, 6, 8, 10, 12, 2, 4, 6, 8, 10, 12] + # Even sizes 2, 4, 6, 8, 10 and 12 (the odd Tier I maximums are not + # asserted; eligibility/ny_heap_income_limit.yaml tests the Tier II column + # at the odd sizes). Published monthly Tier I + # maximums 2,291; 3,482; 4,674; 5,866; 7,057; 8,249 (benefit matrix Tier I + # column; State Plan, page 10) x 12, then one more monthly dollar for each + # size (x 12). + ny_heap_countable_income: [27_492, 41_784, 56_088, 70_392, 84_684, 98_988, 27_504, 41_796, 56_100, 70_404, 84_696, 99_000] + ny_heap_categorically_eligible: [false, false, false, false, false, false, false, false, false, false, false, false] + output: + # The matrix's Tier I column ends at the maximum, so the maximum itself is + # Tier I and one more dollar a month is Tier II. + ny_heap_tier_one: [true, true, true, true, true, true, false, false, false, false, false, false] + +- name: Case 2, categorical eligibility confers Tier I above the Tier I maximum. + period: 2026 + input: + heating_type: NATURAL_GAS + state_code: NY + # $2,500 a month, above the one-person Tier I maximum of 1,695. + ny_heap_countable_income: 30_000 + ny_heap_categorically_eligible: true + output: + # State Plan page 10: the Tier I add-on "is also applied to Regular heater + # benefits received by CE households". + ny_heap_tier_one: true + +- name: Case 3, size fourteen follows the poverty rate rather than the matrix increment. + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY] + ny_heap_household_size: [14, 14] + # 130% of the 2025 guideline for 14 (87,150): floor(1.3 x 87,150 / 12) = + # 9,441 a month, then one more monthly dollar. The matrix's 14+ row adds + # 595 to the size-13 maximum instead (9,440). + ny_heap_countable_income: [113_292, 113_304] + ny_heap_categorically_eligible: [false, false] + output: + ny_heap_tier_one: [true, false] + +# 2024-2025 and 2023-2024 HEAP Monthly Income Eligibility Guidelines +# (Clearinghouse benefit matrices), Tier I column. +# https://liheapch.acf.gov/docs/2025/benefits-matricies/NY_BenefitMatrix_2025.docx +# https://liheapch.acf.gov/docs/2024/benefits-matricies/NY_BenefitMatrix_2024.pdf#page=1 +- name: Case 4, the FY2025 and FY2024 one-person Tier I maximums are inclusive. + period: 2025 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY] + ny_heap_household_size: [1, 1] + # 2024-2025 Tier I maximum 1,631 x 12, then one more monthly dollar. + ny_heap_countable_income: [19_572, 19_584] + ny_heap_categorically_eligible: [false, false] + output: + ny_heap_tier_one: [true, false] + +- name: Case 5, the FY2024 one-person Tier I maximum is inclusive. + period: 2024 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS] + state_code: [NY, NY] + ny_heap_household_size: [1, 1] + # 2023-2024 Tier I maximum 1,579 x 12, then one more monthly dollar. + ny_heap_countable_income: [18_948, 18_960] + ny_heap_categorically_eligible: [false, false] + output: + ny_heap_tier_one: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/payment/ny_heap_vulnerable.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/payment/ny_heap_vulnerable.yaml new file mode 100644 index 00000000000..11fa4e96e45 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/otda/heap/payment/ny_heap_vulnerable.yaml @@ -0,0 +1,37 @@ +# HEAP Manual, Chapter 9 B.3(b) (PDF page 49): vulnerable members are children +# under six, people aged 60 or older, and people receiving SSI or Social +# Security disability payments or meeting the listed VA conditions; Chapter 8 +# E.9(c) (page 45) ignores a nonqualified member's vulnerability. +# https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=49 + +- name: Case 1, existing qualifying benefit pathways establish HEAP disability. + period: 2026 + input: + state_code: [NY, NY, NY, NY, NY, NY, NY] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + age: [40, 40, 40, 40, 40, 40, 40] + receives_ssi: [true, false, false, false, false, false, false] + ssi: [0, 1_200, 0, 0, 0, 0, 0] + social_security_disability: [0, 0, 1_200, 0, 0, 0, 0] + is_permanently_disabled_veteran: [false, false, false, true, false, false, false] + is_surviving_spouse_of_disabled_veteran: [false, false, false, false, true, false, false] + is_surviving_child_of_disabled_veteran: [false, false, false, false, false, true, false] + is_permanently_and_totally_disabled: [false, false, false, false, false, false, true] + output: + # B.3(b)(3): reported SSI, $100 a month of SSI, $100 a month of Social + # Security disability and the three VA conditions each establish + # disability; a disability flag without benefit receipt does not. + ny_heap_vulnerable: [true, true, true, true, true, true, false] + +- name: Case 2, a nonqualified disabled member does not establish vulnerability. + period: 2026 + input: + state_code: NY + heating_type: NATURAL_GAS + age: 40 + is_citizen_or_legal_immigrant: false + ssi: 1_200 + output: + # E.9(c) (page 45): "If the only vulnerable individual is a non-qualified + # alien, the add-on for vulnerability is not included". + ny_heap_vulnerable: false diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_categorically_eligible.py b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_categorically_eligible.py new file mode 100644 index 00000000000..d6f8df579e0 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_categorically_eligible.py @@ -0,0 +1,46 @@ +from policyengine_us.model_api import * + + +class ny_heap_categorically_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP categorical income eligibility" + defined_for = StateCode.NY + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-393.4", + "https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=5", + # PDF pages 37, 110. + "https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37", + ) + documentation = ( + "Receipt of SNAP, TANF or Code A SSI. 18 NYCRR 393.4(c)(1)(iii) and the " + "manual glossary define Code A as an SSI individual or couple living alone " + "in the federal own-household arrangement, so the SPM unit may hold no one " + "but the recipient or the recipient couple, foster members aside. Recurring " + "receipt on the application date is approximated; expedited/emergency-only " + "benefits and roomer-only awards cannot be distinguished. Chapter 8 D.10 " + "also qualifies Safety Net Assistance, but no NY-specific receipt input " + "identifies it." + ) + + def formula(spm_unit, period, parameters): + person = spm_unit.members + arrangement = person("ssi_federal_living_arrangement", period.first_month) + own_household = arrangement == arrangement.possible_values.OWN_HOUSEHOLD + receives_ssi = (person("ssi", period) > 0) | ( + add(person, period, ["receives_ssi"]) > 0 + ) + foster = person("is_in_foster_care", period.first_month) + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + # State Code A is "living alone": one eligible individual or one + # eligible couple (14-ADM-07), so every non-foster member must be an + # SSI recipient who is the head or spouse. + living_alone = spm_unit.all(foster | (receives_ssi & head_or_spouse)) + qualifying_ssi = living_alone & spm_unit.any( + receives_ssi + & own_household + & person("is_citizen_or_legal_immigrant", period) + & ~person("ny_heap_is_excluded_person", period) + ) + return (add(spm_unit, period, ["snap", "tanf"]) > 0) | qualifying_ssi diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_eligible.py b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_eligible.py new file mode 100644 index 00000000000..37165445659 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_eligible.py @@ -0,0 +1,38 @@ +from policyengine_us.model_api import * + + +class ny_heap_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP regular heating eligibility" + defined_for = StateCode.NY + reference = ( + # PDF pages 34, 37, 44, 45, 46, 47, 48. + "https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=34", + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-393.4", + ) + documentation = ( + "Regular heating has no resource test. SPM units approximate energy-sharing " + "households. Application timing, SSN documentation, duplicate payments and the " + "full set of excluded member categories are not modeled." + ) + + def formula(spm_unit, period, parameters): + dwelling = spm_unit("ny_heap_dwelling_type", period) + types = dwelling.possible_values + heat = ( + spm_unit("has_heating_expense", period) + | spm_unit("heat_expense_included_in_rent", period) + | (dwelling == types.ELIGIBLE_GROUP_RESIDENCE) + ) + income_eligible = spm_unit("ny_heap_categorically_eligible", period) | ( + spm_unit("ny_heap_countable_income", period) + <= spm_unit("ny_heap_income_limit", period) + ) + return ( + heat + & income_eligible + & (spm_unit("ny_heap_household_size", period) > 0) + & (dwelling != types.INELIGIBLE_RESIDENCE) + ) diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_household_size.py b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_household_size.py new file mode 100644 index 00000000000..9b58f0ac2d9 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_household_size.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ny_heap_household_size(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP qualified household size" + defined_for = StateCode.NY + # Chapter 8 D.4 and D.9, PDF pages 34, 36, 37, 44; 18 NYCRR 393.4(b). + reference = ( + "https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=34", + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-393.4", + ) + documentation = ( + "SPM members who are citizens or federally qualified noncitizens. Nonqualified " + "members' income still counts in full. Foster members and federal Code C SSI " + "recipients are excluded using existing inputs. Roomers, employees and fleeing " + "felons remain unsupported. The existing immigration enum does not separately " + "identify every additional federally protected status." + ) + + def formula(spm_unit, period, parameters): + person = spm_unit.members + included = ~person("ny_heap_is_excluded_person", period) + qualified = person("is_citizen_or_legal_immigrant", period) + return spm_unit.sum(included & qualified) diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_income_limit.py b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_income_limit.py new file mode 100644 index 00000000000..edd5d385e6b --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_income_limit.py @@ -0,0 +1,36 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class ny_heap_income_limit(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP annualized income limit" + unit = USD + defined_for = StateCode.NY + reference = ( + "https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37", + "https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9", + "https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx", + "https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=2", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ny.otda.heap.eligibility + size = max_(spm_unit("ny_heap_household_size", period), 1) + state = spm_unit.household("state_code_str", period) + base = parameters(period).gov.hhs.smi.amount[state] + # ACF IM 2025-02 Attachment 4 floors the four-person 60% amount before + # the federal size adjustment; this reproduces every published size + # 1-13 limit. + adjusted_smi = smi(size, state, period, parameters) / base + monthly_smi = np.floor( + adjusted_smi * np.floor(base * p.smi_rate) / MONTHS_IN_YEAR + ) + monthly_fpg = np.floor( + spm_unit("ny_heap_fpg", period) * p.fpg_rate / MONTHS_IN_YEAR + ) + # Chapter 8 D.9(c) and the FY2026 plan control sizes 14+, where the + # matrix's additional-person shortcut differs from the stated FPG rate. + return max_(monthly_smi, monthly_fpg) * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_is_excluded_person.py b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_is_excluded_person.py new file mode 100644 index 00000000000..dafa8d590a6 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/eligibility/ny_heap_is_excluded_person.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class ny_heap_is_excluded_person(Variable): + value_type = bool + entity = Person + definition_period = YEAR + label = "Person excluded from the New York HEAP household" + defined_for = StateCode.NY + # Chapter 8 D.4(a)(3), (5), PDF page 36. This is the federal Code C, + # distinct from the state Code A required for categorical SSI eligibility. + reference = ( + "https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=36", + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-393.4", + ) + documentation = ( + "Follows the manual literally: Chapter 8 D.4(a)(5) says federal living " + "arrangement Code C SSI recipients are not household members. 18 NYCRR " + "393.4(b) presumes relatives to be members and exempts only foster care and " + "unrelated roomers or boarders, and D.3(a)(2) (page 35) allows no exception " + "for children under 21, so the regulation would count an SSI child's size and " + "vulnerability. The conflict is recorded in rulespec-us issue 1480." + ) + + def formula(person, period, parameters): + # January living arrangements approximate the application-month status. + foster = person("is_in_foster_care", period.first_month) + arrangement = person("ssi_federal_living_arrangement", period.first_month) + code_c = arrangement == arrangement.possible_values.CHILD_IN_PARENTAL_HOUSEHOLD + receives_ssi = (person("ssi", period) > 0) | ( + add(person, period, ["receives_ssi"]) > 0 + ) + return foster | (code_c & receives_ssi) diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_countable_earned_income.py b/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_countable_earned_income.py new file mode 100644 index 00000000000..1cc0e56e19e --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_countable_earned_income.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class ny_heap_countable_earned_income(Variable): + value_type = float + entity = Person + definition_period = YEAR + label = "New York HEAP countable earnings" + unit = USD + defined_for = StateCode.NY + # PDF pages 37, 39, 42, 43. + reference = ("https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37",) + documentation = ( + "Existing net business income is used without further deductions. " + "HEAP-specific depreciation add-backs, separate accounting periods and wage " + "bonus exclusions are unsupported." + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.otda.heap.income + earnings = 0 + for source in p.sources.earned: + earnings = earnings + max_(person(source, period), 0) + dependent = person("is_tax_unit_dependent", period) + exempt = dependent & ( + (person("age", period) < p.dependent_child_age) + | person("is_full_time_student", period) + ) + return where(exempt, 0, earnings) diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_countable_income.py b/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_countable_income.py new file mode 100644 index 00000000000..507f6191782 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_countable_income.py @@ -0,0 +1,56 @@ +from policyengine_us.model_api import * + + +class ny_heap_countable_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP annualized countable household income" + unit = USD + defined_for = StateCode.NY + reference = ( + # PDF pages 36, 37, 38, 39, 40, 41, 42, 43, 44. + "https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=37", + ) + documentation = ( + "Annual inputs approximate application-month income; final monthly income is " + "rounded down and annualized. Income of nonqualified members counts in full. " + "Social Security and railroad benefits are counted net of the computed " + "Medicare Part B premium; Part D has no variable and stays gross. Each " + "unearned source is floored at zero, so a rental or estate loss does not " + "offset other income. Royalties, regular gifts, aid-and-attendance " + "exclusions and irregular-income exclusions cannot be isolated reliably. No " + "new self-employment or work-expense deduction is applied." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ny.otda.heap.income + person = spm_unit.members + # Chapter 8 D.4 excludes foster members and federal Code C SSI + # recipients. Nonqualified members are excluded only from household + # size; their income still counts in full under D.4(a)(7). + included = ~person("ny_heap_is_excluded_person", period) + # D.14(b)(7) (page 41) converts negative income to zero and lists net + # loss as a deduction that is not allowed, so each source is floored + # like the earned sources: a loss in one source cannot offset another. + unearned = 0 + for source in p.sources.unearned: + unearned = unearned + max_(person(source, period), 0) + # D.12(a)(6) and (8) (page 38) count Social Security and railroad + # benefits after the Medicare Part B and D premiums. The computed + # medicare_part_b_premium is the out-of-pocket Part B premium, zero when + # a Medicare Savings Program pays it; no Part D variable exists. + benefits = max_( + person("social_security", period) + + person("railroad_benefits", period) + - person("medicare_part_b_premium", period), + 0, + ) + income = spm_unit.sum( + (person("ny_heap_countable_earned_income", period) + unearned + benefits) + * included + ) + # TANF is not counted: FY2026 State Plan item 1.9 (page 6) leaves the + # TANF box unchecked, and Chapter 8 D.11(c)(1) (page 37) counts a TA + # grant only for a minor child budgeted as a roomer, which has no input. + return np.floor(income / MONTHS_IN_YEAR) * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_fpg.py b/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_fpg.py new file mode 100644 index 00000000000..c123ceab3f5 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/income/ny_heap_fpg.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class ny_heap_fpg(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP applicable federal poverty guideline" + unit = USD + defined_for = StateCode.NY + reference = ( + # PDF pages 9, 10. + "https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9", + "https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ny.otda.heap.eligibility + size = max_(spm_unit("ny_heap_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/ny/otda/heap/ny_heap.py b/policyengine_us/variables/gov/states/ny/otda/heap/ny_heap.py new file mode 100644 index 00000000000..3e35315bd04 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/ny_heap.py @@ -0,0 +1,56 @@ +from policyengine_us.model_api import * + + +class ny_heap(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP regular heating benefit" + unit = USD + defined_for = "ny_heap_eligible" + reference = ( + "https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx", + # PDF pages 9, 10. + "https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=9", + # PDF pages 45, 46, 47, 48, 49, 84, 87, 88. + "https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=45", + ) + documentation = ( + "Annual regular heating benefit and ordinary Tier I/vulnerability supplements, " + "verified for FY2024 to FY2026; only the Tier I supplement changed across " + "those years. Earlier years are unverified backfilled estimates. Housing " + "assistance approximates subsidized rent (market-rent voucher exceptions are " + "unsupported). An unknown direct-heating fuel returns zero as a coverage gap, " + "tracked in issue 9754; solar falls within other fuels. No bill cap. Crisis, " + "cooling and equipment components are excluded. Mid-year moves and previously " + "advanced nominal payments are not separately tracked." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ny.otda.heap.payment + tier_one = spm_unit("ny_heap_tier_one", period) + fuel = spm_unit("heating_type", period) + # UNSPECIFIED and NONE have a zero base; see #9754 for the default fuel. + base = p.base[fuel] + direct = where( + base > 0, + base + + tier_one * p.tier_one_supplement + + spm_unit("ny_heap_vulnerable", period) * p.vulnerable_supplement, + 0, + ) + subsidized = spm_unit( + "receives_housing_assistance", period + ) | spm_unit.household("is_in_public_housing", period) + dwelling = spm_unit("ny_heap_dwelling_type", period) + group = dwelling == dwelling.possible_values.ELIGIBLE_GROUP_RESIDENCE + heat_included = where( + subsidized | group, + p.heat_included.nominal, + where(tier_one, p.heat_included.tier_one, p.heat_included.tier_two), + ) + return where( + spm_unit("heat_expense_included_in_rent", period) | group, + heat_included, + direct, + ) diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/ny_heap_dwelling_type.py b/policyengine_us/variables/gov/states/ny/otda/heap/ny_heap_dwelling_type.py new file mode 100644 index 00000000000..92413d71b9a --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/ny_heap_dwelling_type.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class NYHEAPDwellingType(Enum): + STANDARD = "Standard residence" + ELIGIBLE_GROUP_RESIDENCE = ( + "HEAP-eligible group residence receiving the nominal payment" + ) + INELIGIBLE_RESIDENCE = "HEAP-ineligible residence" + + +class ny_heap_dwelling_type(Variable): + value_type = Enum + possible_values = NYHEAPDwellingType + default_value = NYHEAPDwellingType.STANDARD + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP dwelling arrangement" + # PDF pages 45, 46, 47; 18 NYCRR 393.4(c)(3)-(4). + reference = ( + "https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=45", + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-393.4", + ) + documentation = ( + "Eligible group residences are the treatment, enriched housing, " + "supervised/supportive living and other settings listed in Chapter 8 F.3 " + "(group living facilities must have at most 16 residents). Ineligible " + "residences include private roomers/boarders, hotels, motels, vehicles, " + "dormitories and congregate care under F.4. Ordinary subsidized housing uses " + "the existing housing-assistance and heat-in-rent inputs." + ) diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/payment/ny_heap_tier_one.py b/policyengine_us/variables/gov/states/ny/otda/heap/payment/ny_heap_tier_one.py new file mode 100644 index 00000000000..ae1cd904e06 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/payment/ny_heap_tier_one.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ny_heap_tier_one(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP Tier I status" + defined_for = StateCode.NY + reference = ( + "https://liheapch.acf.gov/docs/2026/state-plans/NY_Plan_2026.pdf#page=10", + "https://liheapch.acf.gov/docs/2026/benefits-matricies/NY_BenefitMatrix_2026.docx", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ny.otda.heap.payment + threshold = ( + np.floor( + spm_unit("ny_heap_fpg", period) * p.tier_one_fpg_rate / MONTHS_IN_YEAR + ) + * MONTHS_IN_YEAR + ) + return spm_unit("ny_heap_categorically_eligible", period) | ( + spm_unit("ny_heap_countable_income", period) <= threshold + ) diff --git a/policyengine_us/variables/gov/states/ny/otda/heap/payment/ny_heap_vulnerable.py b/policyengine_us/variables/gov/states/ny/otda/heap/payment/ny_heap_vulnerable.py new file mode 100644 index 00000000000..a5b96e8218a --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/otda/heap/payment/ny_heap_vulnerable.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class ny_heap_vulnerable(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "New York HEAP qualified vulnerable member" + defined_for = StateCode.NY + # Chapter 9 B.3(b), PDF page 49; qualified members, pages 44, 45. + reference = ("https://otda.ny.gov/programs/heap/HEAP-manual.pdf#page=49",) + documentation = ( + "The manual adopts the SNAP benefit-receipt disability criteria. Reuses the " + "existing USDA calculation, including its qualifying veteran and survivor " + "flags. A disability flag alone does not establish receipt or certification. " + "The existing USDA flags approximate detailed VA certification; railroad, FECA " + "and disability-based Medicaid pathways remain incomplete." + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ny.otda.heap.payment + person = spm_unit.members + age = person("age", period) + disabled = person("is_usda_disabled", period) + vulnerable = (age < p.young_child_age) | (age >= p.elderly_age) | disabled + return spm_unit.any( + vulnerable + & person("is_citizen_or_legal_immigrant", period) + & ~person("ny_heap_is_excluded_person", period) + )