From 62f77aa70b4f36c91dd75f9294b51c0011108572 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 19:16:06 -0400 Subject: [PATCH 1/7] Add Connecticut CEAP regular heating assistance --- changelog.d/ct-liheap-wave2c.added.md | 1 + .../ct/dss/ceap/eligibility/smi_rate.yaml | 13 + .../ceap/income/earned_income_min_age.yaml | 13 + .../ct/dss/ceap/income/sources/earned.yaml | 18 + .../ct/dss/ceap/income/sources/unearned.yaml | 30 + .../gov/states/ct/dss/ceap/payment/basic.yaml | 25 + .../ct/dss/ceap/payment/fpg_year_lag.yaml | 13 + .../ct/dss/ceap/payment/income_level.yaml | 27 + .../states/ct/dss/ceap/payment/rental.yaml | 25 + .../ceap/payment/vulnerable/elderly_age.yaml | 13 + .../ceap/payment/vulnerable/supplement.yaml | 13 + .../payment/vulnerable/young_child_age.yaml | 13 + policyengine_us/programs.yaml | 10 +- .../gov/states/ct/dss/ceap/ct_ceap.yaml | 1603 +++++++++++++++++ .../ct_ceap_categorically_eligible.yaml | 352 ++++ .../ceap/eligibility/ct_ceap_eligible.yaml | 436 +++++ .../eligibility/ct_ceap_household_size.yaml | 276 +++ .../eligibility/ct_ceap_income_limit.yaml | 41 + .../ceap/income/ct_ceap_countable_income.yaml | 378 ++++ .../ceap/payment/ct_ceap_benefit_level.yaml | 41 + .../gov/states/ct/dss/ceap/ct_ceap.py | 38 + .../ct_ceap_categorically_eligible.py | 21 + .../dss/ceap/eligibility/ct_ceap_eligible.py | 28 + .../eligibility/ct_ceap_household_size.py | 18 + .../ceap/eligibility/ct_ceap_income_limit.py | 26 + .../ceap/income/ct_ceap_countable_income.py | 30 + .../dss/ceap/payment/ct_ceap_benefit_level.py | 21 + 27 files changed, 3522 insertions(+), 1 deletion(-) create mode 100644 changelog.d/ct-liheap-wave2c.added.md create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/income/earned_income_min_age.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/payment/basic.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/payment/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/payment/income_level.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/payment/rental.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/elderly_age.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/supplement.yaml create mode 100644 policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/young_child_age.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.yaml create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.py create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.py create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py diff --git a/changelog.d/ct-liheap-wave2c.added.md b/changelog.d/ct-liheap-wave2c.added.md new file mode 100644 index 00000000000..1127291cef7 --- /dev/null +++ b/changelog.d/ct-liheap-wave2c.added.md @@ -0,0 +1 @@ +Add Connecticut Energy Assistance Program basic and rental heating assistance for fiscal years 2026 and 2027. diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml new file mode 100644 index 00000000000..59a45b0f64e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml @@ -0,0 +1,13 @@ +description: Connecticut limits household income to this share of state median income under the Connecticut Energy Assistance Program. +values: + 2025-10-01: 0.6 + +metadata: + unit: /1 + period: year + label: Connecticut CEAP state median income limit + reference: + - title: Connecticut FY2026 LIHEAP State Plan, Section 2.1 + href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=8 + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Section V + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/earned_income_min_age.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/earned_income_min_age.yaml new file mode 100644 index 00000000000..9988a10e3ff --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/earned_income_min_age.yaml @@ -0,0 +1,13 @@ +description: Connecticut counts earned income from household members this age or older under the Connecticut Energy Assistance Program. +values: + 2025-10-01: 18 + +metadata: + unit: year + period: year + label: Connecticut CEAP minimum age for earned income + reference: + - title: Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 + href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6,7 + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections III-V + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,8,9 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml new file mode 100644 index 00000000000..0e41e4e1701 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml @@ -0,0 +1,18 @@ +description: Connecticut counts these earned income sources under the Connecticut Energy Assistance Program. +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: Connecticut CEAP countable earned income sources + reference: + - title: Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 + href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6,7 + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections III-V + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,8,9 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml new file mode 100644 index 00000000000..94090e9eec9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml @@ -0,0 +1,30 @@ +description: Connecticut counts these unearned income sources under the Connecticut Energy Assistance Program. +values: + 2025-10-01: + - social_security + - unemployment_compensation + - strike_benefits + - pension_income + - survivor_benefits + - workers_compensation + - disability_benefits + - rental_income + - farm_rent_income + - estate_income + - interest_income + - ordinary_dividend_income + - alimony_income + - child_support_received + - financial_assistance + - gambling_winnings + - veterans_benefits + +metadata: + unit: list + period: year + label: Connecticut CEAP countable unearned income sources + reference: + - title: Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 + href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6,7 + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections III-V + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,8,9 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/basic.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/basic.yaml new file mode 100644 index 00000000000..fa6384f2bbb --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/basic.yaml @@ -0,0 +1,25 @@ +description: Connecticut provides this basic heating benefit by income level under the Connecticut Energy Assistance Program. +1: + 2025-10-01: 595 + 2026-10-01: 655 +2: + 2025-10-01: 445 + 2026-10-01: 505 +3: + 2025-10-01: 295 + 2026-10-01: 355 + +metadata: + unit: currency-USD + period: year + label: Connecticut CEAP basic heating benefit + propagate_metadata_to_children: true + breakdown: + - range(1, 4) + breakdown_labels: + - Benefit income level + reference: + - title: Connecticut FY2026 LIHEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections VIII-IX + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=10,11 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/fpg_year_lag.yaml new file mode 100644 index 00000000000..153288aedfd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/fpg_year_lag.yaml @@ -0,0 +1,13 @@ +description: Connecticut uses federal poverty guidelines from this many years before the benefit fiscal year under the Connecticut Energy Assistance Program. +values: + 2025-10-01: 1 + +metadata: + unit: year + period: year + label: Connecticut CEAP federal poverty guideline lag + reference: + - title: Connecticut FY2026 LIHEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections VIII-IX + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=10,11 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/income_level.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/income_level.yaml new file mode 100644 index 00000000000..2b938a0d15d --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/income_level.yaml @@ -0,0 +1,27 @@ +description: Connecticut assigns this benefit level by the ratio of countable income to federal poverty guidelines under the Connecticut Energy Assistance Program. +brackets: + - threshold: + 2025-10-01: -.inf + amount: + 2025-10-01: 1 + - threshold: + 2025-10-01: 1.25 + amount: + 2025-10-01: 2 + - threshold: + 2025-10-01: 2 + amount: + 2025-10-01: 3 + +metadata: + unit: /1 + period: year + label: Connecticut CEAP benefit income level + type: single_amount + threshold_unit: /1 + amount_unit: /1 + reference: + - title: Connecticut FY2026 LIHEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections VIII-IX + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=10,11 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/rental.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/rental.yaml new file mode 100644 index 00000000000..5817f6acea5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/rental.yaml @@ -0,0 +1,25 @@ +description: Connecticut provides this rental heating benefit by income level under the Connecticut Energy Assistance Program. +1: + 2025-10-01: 125 + 2026-10-01: 140 +2: + 2025-10-01: 100 + 2026-10-01: 115 +3: + 2025-10-01: 75 + 2026-10-01: 90 + +metadata: + unit: currency-USD + period: year + label: Connecticut CEAP rental heating benefit + propagate_metadata_to_children: true + breakdown: + - range(1, 4) + breakdown_labels: + - Benefit income level + reference: + - title: Connecticut FY2026 LIHEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections VIII-IX + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=10,11 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/elderly_age.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/elderly_age.yaml new file mode 100644 index 00000000000..af2e3b3fefe --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/elderly_age.yaml @@ -0,0 +1,13 @@ +description: Connecticut treats household members this age or older as vulnerable under the Connecticut Energy Assistance Program. +values: + 2025-10-01: 60 + +metadata: + unit: year + period: year + label: Connecticut CEAP elderly age threshold + reference: + - title: Connecticut FY2026 LIHEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections VIII-IX + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=10,11 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/supplement.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/supplement.yaml new file mode 100644 index 00000000000..2ce29f0b94e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/supplement.yaml @@ -0,0 +1,13 @@ +description: Connecticut adds this amount to basic heating assistance for households with a vulnerable member under the Connecticut Energy Assistance Program. +values: + 2025-10-01: 50 + +metadata: + unit: currency-USD + period: year + label: Connecticut CEAP vulnerable household supplement + reference: + - title: Connecticut FY2026 LIHEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections VIII-IX + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=10,11 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/young_child_age.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/young_child_age.yaml new file mode 100644 index 00000000000..d51283b2569 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/payment/vulnerable/young_child_age.yaml @@ -0,0 +1,13 @@ +description: Connecticut treats children below this age as vulnerable under the Connecticut Energy Assistance Program. +values: + 2025-10-01: 6 + +metadata: + unit: year + period: year + label: Connecticut CEAP young child age threshold + reference: + - title: Connecticut FY2026 LIHEAP Benefit Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Sections VIII-IX + href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=10,11 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 756dc2c4988..5edd0ab0c30 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -802,7 +802,7 @@ programs: category: Benefits agency: HHS status: partial - coverage: OR, DC, Riverside County, MA, IL, KS, MS, TX + coverage: OR, DC, Riverside County, MA, IL, KS, MS, TX, CT state_implementations: - state: OR status: in_progress @@ -846,6 +846,14 @@ programs: variable: tx_ceap parameter_prefix: gov.states.tx.tdhca.ceap notes: Models the FPG income limit, the FY2024-only SMI limit, benefit amounts, and categorical eligibility through TANF enrollment, SNAP eligibility, and SSI receipt. Not modeled - net rather than gross gambling winnings, the Medicare premium deduction from counted Social Security, and the exclusion of means-tested veterans' pensions from counted income (10 TAC 6.4(c)) + - state: CT + status: partial + name: Connecticut CEAP + full_name: Connecticut Energy Assistance Program + variable: ct_ceap + parameter_prefix: gov.states.ct.dss.ceap + verified_years: "2026-2027" + notes: Regular basic and rental heating assistance. Annual income and primary-fuel expenses approximate application income and covered-season costs. Detailed household exclusions, VA pension subtypes, Medicare deductions and prior awards are not fully represented. The separate nominal SNAP grant, crisis assistance and equipment are outside this implementation. # --- SSA programs --- - id: ssi diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml new file mode 100644 index 00000000000..d1b6e63993c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml @@ -0,0 +1,1603 @@ +# REQ-001-011. Independent end-to-end source scenarios; no CEAP intermediates supplied as inputs. +# Sources: +# - https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,9,10,11,15 +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 1, FY2026 level 1 direct heating grant. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 0 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 1 + ct_ceap_eligible: true + ct_ceap: 595 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 2, FY2026 level 1 rental grant. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 0 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 1 + ct_ceap_eligible: true + ct_ceap: 125 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 3, FY2026 level 2 direct heating grant. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 20_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 2 + ct_ceap_eligible: true + ct_ceap: 445 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 4, FY2026 level 2 rental grant. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 20_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 2 + ct_ceap_eligible: true + ct_ceap: 100 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 5, FY2026 level 3 direct heating grant. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 40_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 40_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 3 + ct_ceap_eligible: true + ct_ceap: 295 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 6, FY2026 level 3 rental grant. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 40_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 40_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 3 + ct_ceap_eligible: true + ct_ceap: 75 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 7, FY2027 level 1 direct heating grant. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + employment_income: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 0 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 1 + ct_ceap_eligible: true + ct_ceap: 655 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 8, FY2027 level 1 rental grant. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + employment_income: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 0 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 1 + ct_ceap_eligible: true + ct_ceap: 140 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 9, FY2027 level 2 direct heating grant. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 20_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 2 + ct_ceap_eligible: true + ct_ceap: 505 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 10, FY2027 level 2 rental grant. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 20_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 2 + ct_ceap_eligible: true + ct_ceap: 115 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 11, FY2027 level 3 direct heating grant. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + employment_income: 40_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 40_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 3 + ct_ceap_eligible: true + ct_ceap: 355 + +# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +- name: Case 12, FY2027 level 3 rental grant. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + employment_income: 40_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 40_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 3 + ct_ceap_eligible: true + ct_ceap: 90 + +# REQ-007: age 60 meets elderly boundary; Level 1 basic plus 50. +- name: Case 13, FY2026 elderly member receives fifty dollar supplement. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 645 + +# REQ-007: age 60 meets elderly boundary; Level 1 basic plus 50. +- name: Case 14, FY2027 elderly member receives fifty dollar supplement. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 705 + +# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +- name: Case 15, age just below sixty is not elderly. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 59.99 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 595 + +# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +- name: Case 16, disabled adult receives vulnerability supplement. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: true + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 645 + +# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +- name: Case 17, child just below six receives vulnerability supplement. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 5.99 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap: 645 + +# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +- name: Case 18, child at six no longer supplies young child supplement. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 6 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap: 595 + +# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +- name: Case 19, multiple vulnerable members receive one supplement. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + immigration_status: CITIZEN + is_disabled: true + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 5 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap: 645 + +# REQ-008: rental Level 1 is 125, no 50 dollar supplement and no exclusion based only on housing assistance. +- name: Case 20, vulnerable subsidized rental household receives rental amount only. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + receives_housing_assistance: true + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 125 + +# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +- name: Case 21, gas bill below schedule caps retained grant. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 100 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 100 + +# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +- name: Case 22, gas bill exactly at schedule pays full amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 595 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 595 + +# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +- name: Case 23, gas bill above schedule does not increase grant. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 596 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 595 + +# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +- name: Case 24, fuel oil selects oil expense not larger gas bill. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: FUEL_OIL + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + fuel_oil_expense: 100 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 100 + +# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +- name: Case 25, electric heating uses pre subsidy electricity expense. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + pre_subsidy_electricity_expense: 200 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 200 + +# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +- name: Case 26, wood heating uses wood expense. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: WOOD + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + wood_expense: 300 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 300 + +# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +- name: Case 27, no direct heating expense yields no benefit. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 0 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap: 0 + +# REQ-006/007: positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. +- name: Case 28, snap receipt bypasses income ceiling but retains level three. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 100_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 120 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 100_000 + ct_ceap_categorically_eligible: true + ct_ceap_benefit_level: 3 + ct_ceap: 295 + +# REQ-006/008: rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. +- name: Case 29, snap does not bypass rental income ceiling. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 100_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 120 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: false + ct_ceap_eligible: false + ct_ceap: 0 + +# REQ-006/007: positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. +- name: Case 30, ct_tfa receipt bypasses income ceiling but retains level three. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 100_000 + person2: + age: 10 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 120 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_countable_income: 100_000 + ct_ceap_categorically_eligible: true + ct_ceap_benefit_level: 3 + ct_ceap: 295 + +# REQ-006/008: rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. +- name: Case 31, ct_tfa does not bypass rental income ceiling. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 100_000 + person2: + age: 10 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 120 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_categorically_eligible: false + ct_ceap_eligible: false + ct_ceap: 0 + +# REQ-006/007: positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. +- name: Case 32, ssi receipt bypasses income ceiling but retains level three. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: true + is_in_foster_care: + 2026-01: false + ssi: + '2026': 120 + social_security: 0 + employment_income: 100_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 100_000 + ct_ceap_categorically_eligible: true + ct_ceap_benefit_level: 3 + ct_ceap: 345 + +# REQ-006/008: rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. +- name: Case 33, ssi does not bypass rental income ceiling. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: true + is_in_foster_care: + 2026-01: false + ssi: + '2026': 120 + social_security: 0 + employment_income: 100_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: false + ct_ceap_eligible: false + ct_ceap: 0 + +# REQ-006/007: positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. +- name: Case 34, ct_ssp receipt bypasses income ceiling but retains level three. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 100_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 120 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 100_000 + ct_ceap_categorically_eligible: true + ct_ceap_benefit_level: 3 + ct_ceap: 345 + +# REQ-006/008: rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. +- name: Case 35, ct_ssp does not bypass rental income ceiling. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 100_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 120 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: false + ct_ceap_eligible: false + ct_ceap: 0 + +# REQ-001/007: size 1, income 20,000 gives Level 2; qualified young child adds 50 to 445. +- name: Case 36, citizen child with nonqualified parent uses child size and all income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: UNDOCUMENTED + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 20_000 + person2: + age: 5 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_countable_income: 20_000 + ct_ceap_household_size: 1 + ct_ceap_income_limit: 47_764 + ct_ceap_benefit_level: 2 + ct_ceap: 495 + +# REQ-001/007: excluded elder is not a member for vulnerability. +- name: Case 37, nonqualified elder does not establish vulnerability. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 65 + immigration_status: UNDOCUMENTED + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_household_size: 1 + ct_ceap: 595 + +# REQ-001: removing foster child excludes 30,000 unearned income and young-child supplement; remaining adult gets Level 2 basic 445. +- name: Case 38, represented foster child excluded from income size and vulnerability. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 20_000 + person2: + age: 5 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: true + ssi: + '2026': 0 + social_security: 30_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_countable_income: 20_000 + ct_ceap_household_size: 1 + ct_ceap_benefit_level: 2 + ct_ceap: 445 + +# REQ-001/011: each SPM unit belongs to its own state household; all CT variables are state-guarded. +- name: Case 39, mixed state batch isolates Connecticut calculation. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person3: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit1: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + spm_unit2: + members: [person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + spm_unit3: + members: [person3] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household1: + members: [person1] + state_code: CT + household2: + members: [person2] + state_code: MA + household3: + members: [person3] + state_code: NY + output: + ct_ceap_countable_income: [0, 0, 0] + ct_ceap_household_size: [1, 0, 0] + ct_ceap_income_limit: [47_764, 0, 0] + ct_ceap_categorically_eligible: [false, false, false] + ct_ceap_eligible: [true, false, false] + ct_ceap_benefit_level: [1, 0, 0] + ct_ceap: [595, 0, 0] + +# REQ-001/006: represented foster members are outside the energy household. +# The adult has 100,000 countable income and no qualifying receipt of their own. +- name: Case 40, represented foster SSI does not establish categorical receipt. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + employment_income: 100_000 + social_security: 0 + ssi: + '2026': 0 + is_in_foster_care: + 2026-01: false + person2: + age: 5 + immigration_status: CITIZEN + is_disabled: true + social_security: 0 + ssi: + '2026': 120 + is_in_foster_care: + 2026-01: true + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_countable_income: 100_000 + ct_ceap_household_size: 1 + ct_ceap_categorically_eligible: false + ct_ceap_eligible: false + ct_ceap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml new file mode 100644 index 00000000000..07effcc2209 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml @@ -0,0 +1,352 @@ +# REQ-006. P26 physical p5; A26/A27 IV and IX direct-vendor exception. +# Sources: +# - https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=5,6,7 +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,9,10,11,15 +# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +- name: Case 1, snap receipt with direct heating. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 120 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: true + +# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +- name: Case 2, snap receipt with heat included in rent. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: true + snap: + '2026': 120 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: false + +# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +- name: Case 3, ct_tfa receipt with direct heating. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 10 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 120 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_categorically_eligible: true + +# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +- name: Case 4, ct_tfa receipt with heat included in rent. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 10 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 120 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_categorically_eligible: false + +# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +- name: Case 5, ssi receipt with direct heating. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: true + is_in_foster_care: + 2026-01: false + ssi: + '2026': 120 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: true + +# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +- name: Case 6, ssi receipt with heat included in rent. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: true + is_in_foster_care: + 2026-01: false + ssi: + '2026': 120 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: false + +# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +- name: Case 7, ct_ssp receipt with direct heating. + period: 2026 + input: + people: + person1: + age: 65 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 120 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: true + +# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +- name: Case 8, ct_ssp receipt with heat included in rent. + period: 2026 + input: + people: + person1: + age: 65 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 120 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: false + +# REQ-006. +- name: Case 9, no qualifying receipt has no categorical exception. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: false + +# REQ-004/006: generic VA does not identify the required means-tested program. +- name: Case 10, generic veterans benefits do not establish categorical receipt. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + veterans_benefits: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.yaml new file mode 100644 index 00000000000..63016ff3d75 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.yaml @@ -0,0 +1,436 @@ +# REQ-001/005/006/008/009. State, membership, income and heating responsibility. +# Sources: +# - https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,9,10,11,15 +# REQ-005: published one-person SMI ceiling is inclusive. +- name: Case 1, FY2026 income at ceiling eligible. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 47_764 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: true + +# REQ-005: published one-person SMI ceiling is inclusive. +- name: Case 2, FY2026 income one cent over ceiling ineligible. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 47_764.01 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false + +# REQ-005: published one-person SMI ceiling is inclusive. +- name: Case 3, FY2027 income at ceiling eligible. + period: 2027 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + employment_income: 48_714 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: true + +# REQ-005: published one-person SMI ceiling is inclusive. +- name: Case 4, FY2027 income one cent over ceiling ineligible. + period: 2027 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2027-01: false + ssi: + '2027': 0 + social_security: 0 + employment_income: 48_714.01 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2027': 0 + ct_tfa: + '2027': 0 + ct_ssp: + '2027': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false + +# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +- name: Case 5, known direct fuel with positive matching cost. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: true + +# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +- name: Case 6, direct fuel with zero matching cost. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 0 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false + +# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +- name: Case 7, direct fuel with negative matching cost. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: -100 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false + +# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +- name: Case 8, affirmative no heating despite reported bills. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NONE + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false + +# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +- name: Case 9, unknown direct fuel does not establish a heating bill. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false + +# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +- name: Case 10, rental with unknown fuel and no separate cost. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: true + +# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +- name: Case 11, rental with affirmative no heat. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NONE + gas_expense: 0 + heat_expense_included_in_rent: true + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false + +# REQ-001/006: categorical receipt does not waive qualified membership. +- name: Case 12, no qualified members ineligible despite SNAP receipt. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: UNDOCUMENTED + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 120 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false + +# REQ-006/009. +- name: Case 13, categorical receipt does not waive heating responsibility. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 0 + heat_expense_included_in_rent: false + snap: + '2026': 120 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml new file mode 100644 index 00000000000..99361d21093 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml @@ -0,0 +1,276 @@ +# REQ-001. A26/A27 III and V.J-K; qualified membership and represented foster exclusion. +# Sources: +# - https://www.cga.ct.gov/app/related/20250616_2025%20Block%20Grants%20and%20Waiver%20Applications/FFY%202026%20LIHEAP%20Allocation%20Plan.pdf#page=5,9 +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,9,10,11,15 +# REQ-001: count qualified members, excluding represented foster members. +- name: Case 1, citizen and qualified noncitizens count. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 38 + immigration_status: LEGAL_PERMANENT_RESIDENT + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person3: + age: 17 + immigration_status: REFUGEE + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2, person3] + state_code: CT + output: + ct_ceap_household_size: 3 + +# REQ-001: count qualified members, excluding represented foster members. +- name: Case 2, undocumented parent does not count but citizen child does. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: UNDOCUMENTED + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 38 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_household_size: 1 + +# REQ-001: count qualified members, excluding represented foster members. +- name: Case 3, all nonqualified members yield zero size. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: UNDOCUMENTED + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 38 + immigration_status: DACA + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_household_size: 0 + +# REQ-001: count qualified members, excluding represented foster members. +- name: Case 4, represented foster child is excluded. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 38 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: true + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_household_size: 1 + +# REQ-001: count qualified members, excluding represented foster members. +- name: Case 5, eight qualified household members count. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person2: + age: 38 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person3: + age: 17 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person4: + age: 15 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person5: + age: 12 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person6: + age: 10 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person7: + age: 8 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + person8: + age: 6 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: CT + output: + ct_ceap_household_size: 8 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.yaml new file mode 100644 index 00000000000..2f933b15f44 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.yaml @@ -0,0 +1,41 @@ +# REQ-005. M26 and A27 physical p7 published annual income ceilings. +# Sources: +# - https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,9,10,11,15 +# REQ-005: source table amounts, not values evaluated from the model formula. +- name: Case 1, all eight published FY2026 household income limits. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [CT, CT, CT, CT, CT, CT, CT, CT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + ct_ceap_household_size: [1, 2, 3, 4, 5, 6, 7, 8] + output: + ct_ceap_income_limit: [47_764, 62_460, 77_157, 91_854, 106_550, 121_247, 124_002, 126_758] + +# REQ-005: source table amounts, not values evaluated from the model formula. +- name: Case 2, all eight published FY2027 household income limits. + period: 2027 + absolute_error_margin: 0.01 + input: + state_code: [CT, CT, CT, CT, CT, CT, CT, CT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + ct_ceap_household_size: [1, 2, 3, 4, 5, 6, 7, 8] + output: + ct_ceap_income_limit: [48_714, 63_703, 78_692, 93_681, 108_669, 123_658, 126_469, 129_279] + +# REQ-001/005: eligibility requires a positive qualified household size. +- name: Case 3, no qualified members have no income allowance. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: CT + heating_type: NATURAL_GAS + gas_expense: 1_000 + ct_ceap_household_size: 0 + output: + ct_ceap_income_limit: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml new file mode 100644 index 00000000000..0a472d76736 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml @@ -0,0 +1,378 @@ +# REQ-001-004. P26 physical pp6-7 checkbox source list; A26/A27 III. +# Sources: +# - https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=5,6,7 +# - https://www.cga.ct.gov/app/related/20250616_2025%20Block%20Grants%20and%20Waiver%20Applications/FFY%202026%20LIHEAP%20Allocation%20Plan.pdf#page=5,9 +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,9,10,11,15 +# REQ-002: 1,000 + 2,000 + 3,000 + 4,000 + 5,000 = 15,000. +- name: Case 1, adult earned sources all count. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 1_000 + self_employment_income: 2_000 + sstb_self_employment_income: 3_000 + farm_operations_income: 4_000 + partnership_s_corp_income: 5_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 15_000 + +# REQ-003/004: 100 + 200 + ... + 1,700 = 15,300. Generic VA is countable under the documented input limitation. +- name: Case 2, supported disjoint unearned sources count once. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 100 + unemployment_compensation: 200 + strike_benefits: 300 + pension_income: 400 + survivor_benefits: 500 + workers_compensation: 600 + disability_benefits: 700 + rental_income: 800 + farm_rent_income: 900 + estate_income: 1_000 + interest_income: 1_100 + ordinary_dividend_income: 1_200 + alimony_income: 1_300 + child_support_received: 1_400 + financial_assistance: 1_500 + gambling_winnings: 1_600 + veterans_benefits: 1_700 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 15_300 + +# REQ-003: 1,200 taxable + 300 exempt pension = 1,500, without counting the aggregate twice. +- name: Case 3, pension components aggregate once. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + taxable_pension_income: 1_200 + tax_exempt_pension_income: 300 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 1_500 + +# REQ-002/003: 10,000 adult wages + 1,000 child Social Security + 2,000 child support = 13,000. +- name: Case 4, child earned income excluded but unearned retained. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 10_000 + person2: + age: 17.99 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 1_000 + employment_income: 20_000 + self_employment_income: 1_000 + child_support_received: 2_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_countable_income: 13_000 + +# REQ-002: 20,000 + 1,000 earned and 3,000 unearned = 24,000 at age 18. +- name: Case 5, earned income counts at age eighteen. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 18 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 1_000 + employment_income: 20_000 + self_employment_income: 1_000 + child_support_received: 2_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 24_000 + +# REQ-002: 10,000 wages + 2,000 SSTB + 1,000 partnership = 13,000; losses contribute zero. +- name: Case 6, business losses do not offset other earnings. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 10_000 + self_employment_income: -5_000 + sstb_self_employment_income: 2_000 + farm_operations_income: -3_000 + partnership_s_corp_income: 1_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 13_000 + +# REQ-003: P26 countable-income checklist leaves SSI, TANF and general assistance unchecked. +- name: Case 7, SSI TFA and general assistance excluded. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: true + is_in_foster_care: + 2026-01: false + ssi: + '2026': 12_000 + social_security: 0 + employment_income: 1_000 + general_assistance: 2_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 6_000 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 1_000 + +# REQ-001: all 20,000 of excluded-from-size parent wages plus 1,000 child support counts. +- name: Case 8, nonqualified members income fully counts. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: UNDOCUMENTED + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 20_000 + person2: + age: 5 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + child_support_received: 1_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_countable_income: 21_000 + +# REQ-001: foster member is outside the energy household, including the members 8,000 unearned income. +- name: Case 9, represented foster income excluded. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + social_security: 0 + employment_income: 10_000 + person2: + age: 17 + immigration_status: CITIZEN + is_disabled: false + is_in_foster_care: + 2026-01: true + ssi: + '2026': 0 + social_security: 6_000 + child_support_received: 2_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + ct_tfa: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1, person2] + state_code: CT + output: + ct_ceap_countable_income: 10_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.yaml new file mode 100644 index 00000000000..30d98e2cb4e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.yaml @@ -0,0 +1,41 @@ +# REQ-007/011. M26 and A27 pp7,10-11; prior-year FPG thresholds. +# Sources: +# - https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,6,7,9,10,11,15 +# REQ-007/011: prior-year FPG; 125% boundary 19,562.50, 200% boundary 31,300.00. +- name: Case 1, FY2026 inclusive poverty boundaries and no gaps. + period: 2026 + input: + state_code: [CT, CT, CT, CT, CT, CT, CT, CT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + ct_ceap_household_size: [1, 1, 1, 1, 1, 1, 1, 1] + ct_ceap_countable_income: [0, 19562.49, 19562.5, 19562.51, 31299.99, 31_300, 31300.01, 100_000] + output: + ct_ceap_benefit_level: [1, 1, 1, 2, 2, 2, 3, 3] + +# REQ-007/011: prior-year FPG; 125% boundary 19,950.00, 200% boundary 31,920.00. +- name: Case 2, FY2027 inclusive poverty boundaries and no gaps. + period: 2027 + input: + state_code: [CT, CT, CT, CT, CT, CT, CT, CT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + ct_ceap_household_size: [1, 1, 1, 1, 1, 1, 1, 1] + ct_ceap_countable_income: [0, 19949.99, 19_950, 19950.01, 31919.99, 31_920, 31920.01, 100_000] + output: + ct_ceap_benefit_level: [1, 1, 1, 2, 2, 2, 3, 3] + +# REQ-007: 2025 two-person FPG is 15,650 + 5,500 = 21,150; multiply by 1.25 and 2. +- name: Case 3, two person family uses additional person FPG. + period: 2026 + input: + state_code: [CT, CT, CT, CT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000] + ct_ceap_household_size: [2, 2, 2, 2] + ct_ceap_countable_income: [26437.5, 26437.51, 42_300, 42300.01] + output: + ct_ceap_benefit_level: [1, 2, 2, 3] diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py b/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py new file mode 100644 index 00000000000..46cdecd7164 --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py @@ -0,0 +1,38 @@ +from policyengine_us.model_api import * + + +class ct_ceap(Variable): + value_type = float + entity = SPMUnit + label = "Connecticut Energy Assistance Program regular heating benefit" + unit = USD + definition_period = YEAR + defined_for = "ct_ceap_eligible" + reference = "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=6,10,11,15" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ct.dss.ceap.payment + # State-scoped helpers return zero on other-state rows in a mixed + # simulation. Keep all vectorized lookups valid before eligibility masks. + level = max_(spm_unit("ct_ceap_benefit_level", period), 1) + person = spm_unit.members + age = person("age", period) + qualified = person("is_citizen_or_legal_immigrant", period) + qualified = qualified & ~person("is_in_foster_care", period.first_month) + vulnerable = spm_unit.any( + qualified + & ( + (age >= p.vulnerable.elderly_age) + | (age < p.vulnerable.young_child_age) + | person("is_disabled", period) + ) + ) + basic = p.basic[level] + vulnerable * p.vulnerable.supplement + # Utility credits exceeding covered-season charges must be returned; + # delivered-fuel payments cover actual deliveries. Annual primary-fuel + # expense approximates covered-season cost and oil vendor pricing. + direct_payment = min_(basic, max_(spm_unit("heating_expense", period), 0)) + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + # Rental cash grants have no bill cap. Prior awards/moves, the separate + # SNAP nominal payment, crisis, weatherization and equipment are excluded. + return where(heat_in_rent, p.rental[level], direct_payment) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py new file mode 100644 index 00000000000..f5e5a7fe847 --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ct_ceap_categorically_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Categorically eligible for Connecticut CEAP" + definition_period = YEAR + defined_for = StateCode.CT + reference = "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=6,7,11" + + def formula(spm_unit, period, parameters): + # Positive annual receipt approximates receipt at application. + # Refugee Cash Assistance and means-tested VA receipt are unavailable; + # generic veterans_benefits does not establish VA eligibility. + person = spm_unit.members + member = ~person("is_in_foster_care", period.first_month) + ssi = spm_unit.sum(member * person("ssi", period, options=[ADD])) + receipt = add(spm_unit, period, ["snap", "ct_tfa", "ct_ssp"]) + ssi > 0 + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + return receipt & ~heat_in_rent diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py new file mode 100644 index 00000000000..9b7117b0e84 --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class ct_ceap_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Connecticut CEAP basic or rental heating assistance" + definition_period = YEAR + defined_for = StateCode.CT + reference = "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7,9,11,15" + + def formula(spm_unit, period, parameters): + size = spm_unit("ct_ceap_household_size", period) + income = spm_unit("ct_ceap_countable_income", period) + limit = spm_unit("ct_ceap_income_limit", period) + categorical = spm_unit("ct_ceap_categorically_eligible", period) + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + expense = spm_unit("heating_expense", period) + heating_type = spm_unit("heating_type", period) + has_heat = heating_type != heating_type.possible_values.NONE + # Subsidized renters are not independently excluded. Heat-in-rent covers + # verified rental heating costs; landlord/account verification is assumed. + return ( + (size > 0) + & ((income <= limit) | categorical) + & (heat_in_rent | (expense > 0)) + & has_heat + ) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.py new file mode 100644 index 00000000000..58f2590952b --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ct_ceap_household_size(Variable): + value_type = int + entity = SPMUnit + label = "Connecticut CEAP household size" + definition_period = YEAR + defined_for = StateCode.CT + reference = "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,9" + # The SPM unit approximates the common energy household. Boarders and other + # institutional residents need additional household-construction facts. + + def formula(spm_unit, period, parameters): + person = spm_unit.members + qualified = person("is_citizen_or_legal_immigrant", period) + foster = person("is_in_foster_care", period.first_month) + return spm_unit.sum(qualified & ~foster) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.py new file mode 100644 index 00000000000..dd6652cf0f0 --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class ct_ceap_income_limit(Variable): + value_type = float + entity = SPMUnit + label = "Connecticut CEAP income limit" + unit = USD + definition_period = YEAR + defined_for = StateCode.CT + reference = ( + "https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf", + "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7", + ) + + def formula(spm_unit, period, parameters): + size = spm_unit("ct_ceap_household_size", period) + state = spm_unit.household("state_code_str", period) + p = parameters(period) + base = p.gov.hhs.smi.amount[state] + factor = smi(size, state, period, parameters) / base + # This order reproduces every published FY2026/FY2027 size 1-8 limit; + # the source prints the amounts but does not specify the rounding order. + amount = np.floor(base * p.gov.states.ct.dss.ceap.eligibility.smi_rate) + return where(size > 0, np.floor(amount * factor), 0) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py b/policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py new file mode 100644 index 00000000000..11233258048 --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class ct_ceap_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "Connecticut CEAP countable income" + unit = USD + definition_period = YEAR + defined_for = StateCode.CT + reference = ( + "https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6,7", + "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5,8,9", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ct.dss.ceap.income + person = spm_unit.members + # Annual inputs approximate the permitted 52-week assessment. Existing + # net business inputs are used without further business-cost deductions. + earned = sum(max_(person(source, period), 0) for source in p.sources.earned) + adult = person("age", period) >= p.earned_income_min_age + member = ~person("is_in_foster_care", period.first_month) + unearned = add(person, period, p.sources.unearned) + # Nonqualified members' income counts in full. SSI, TFA and general + # assistance are excluded by the model plan's income checklist. + # Medicare premiums, excluded VA pension subtypes, gross rental receipts, + # in-kind support and separately identified jury/settlement/insurance/ + # AmeriCorps receipts cannot be resolved by these existing income inputs. + return max_(spm_unit.sum(member * (where(adult, earned, 0) + unearned)), 0) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py b/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py new file mode 100644 index 00000000000..b57e8b2bf66 --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class ct_ceap_benefit_level(Variable): + value_type = int + entity = SPMUnit + label = "Connecticut CEAP benefit level" + definition_period = YEAR + defined_for = StateCode.CT + reference = "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7,10,11" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ct.dss.ceap.payment + size = spm_unit("ct_ceap_household_size", period) + group = spm_unit.household("state_group_str", period) + guideline = fpg( + max_(size, 1), group, period, parameters, year_lag=p.fpg_year_lag + ) + income = spm_unit("ct_ceap_countable_income", period) + return p.income_level.calc(income / guideline, right=True) From 4241855325f8bf35dbe35504a1de3eb4adec2b3e Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 19:32:41 -0400 Subject: [PATCH 2/7] Correct Connecticut categorical benefit and foster SSP treatment --- .../ct/dss/ceap/eligibility/smi_rate.yaml | 2 +- .../gov/states/ct/dss/ceap/ct_ceap.yaml | 565 ++++++++++++++++++ .../ct_ceap_categorically_eligible.py | 8 +- .../dss/ceap/payment/ct_ceap_benefit_level.py | 6 +- 4 files changed, 578 insertions(+), 3 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml index 59a45b0f64e..71bb510e033 100644 --- a/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml @@ -8,6 +8,6 @@ metadata: label: Connecticut CEAP state median income limit reference: - title: Connecticut FY2026 LIHEAP State Plan, Section 2.1 - href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=8 + href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=9 - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Section V href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml index d1b6e63993c..8d85b5e0e29 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml @@ -1601,3 +1601,568 @@ ct_ceap_categorically_eligible: false ct_ceap_eligible: false ct_ceap: 0 + +# Independent review C1/C3 examples: FY2026 matrix categorical footnote and +# allocation plan household exclusion, physical pages 5-7. All receipts computed. +# - https://www.cga.ct.gov/app/related/20250616_2025%20Block%20Grants%20and%20Waiver%20Applications/FFY%202026%20LIHEAP%20Allocation%20Plan.pdf#page=5,6,7 +# C1: 10 * 13,600 = 136,000 > floor(91,854 * 1.47) = 135,025; +# categorical level 3 basic 295 + vulnerable 50 = 345 (not FPG level 2). +# C3: foster SSI/SSP excluded; remaining member income 100,000 > 47,764. +- name: Above-SMI categorical large household receives level 3 + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person2: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person3: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person4: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person5: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person6: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person7: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person8: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person9: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person10: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 13600 + social_security: + '2026': 0 + is_disabled: + '2026': false + meets_ssi_disability_criteria: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + person11: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 0 + social_security: + '2026': 0 + is_disabled: + '2026': true + meets_ssi_disability_criteria: + '2026': true + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + spm_units: + unit: + members: + - person1 + - person2 + - person3 + - person4 + - person5 + - person6 + - person7 + - person8 + - person9 + - person10 + - person11 + heating_type: + '2026': NATURAL_GAS + gas_expense: + '2026': 1000 + heat_expense_included_in_rent: + '2026': false + households: + household: + members: + - person1 + - person2 + - person3 + - person4 + - person5 + - person6 + - person7 + - person8 + - person9 + - person10 + - person11 + state_code: + '2026': CT + tax_units: + person1: + members: + - person1 + person2: + members: + - person2 + person3: + members: + - person3 + person4: + members: + - person4 + person5: + members: + - person5 + person6: + members: + - person6 + person7: + members: + - person7 + person8: + members: + - person8 + person9: + members: + - person9 + person10: + members: + - person10 + person11: + members: + - person11 + marital_units: + person1: + members: + - person1 + person2: + members: + - person2 + person3: + members: + - person3 + person4: + members: + - person4 + person5: + members: + - person5 + person6: + members: + - person6 + person7: + members: + - person7 + person8: + members: + - person8 + person9: + members: + - person9 + person10: + members: + - person10 + person11: + members: + - person11 + families: + person1: + members: + - person1 + person2: + members: + - person2 + person3: + members: + - person3 + person4: + members: + - person4 + person5: + members: + - person5 + person6: + members: + - person6 + person7: + members: + - person7 + person8: + members: + - person8 + person9: + members: + - person9 + person10: + members: + - person10 + person11: + members: + - person11 + output: + ct_ceap_household_size: 11 + ct_ceap_countable_income: 136000 + ct_ceap_income_limit: 135025 + ct_ceap_categorically_eligible: true + ct_ceap_benefit_level: 3 + ct_ceap: 345 + +- name: Excluded foster adult SSP cannot establish categorical eligibility + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 100000 + social_security: + '2026': 0 + is_disabled: + '2026': false + is_blind: + '2026': false + is_in_foster_care: + 2026-01: false + 2026-02: false + 2026-03: false + 2026-04: false + 2026-05: false + 2026-06: false + 2026-07: false + 2026-08: false + 2026-09: false + 2026-10: false + 2026-11: false + 2026-12: false + takes_up_ssi_if_eligible: + '2026': false + person2: + age: + '2026': 40 + immigration_status: + '2026': CITIZEN + employment_income: + '2026': 0 + social_security: + '2026': 0 + is_disabled: + '2026': true + meets_ssi_disability_criteria: + '2026': true + is_in_foster_care: + 2026-01: true + 2026-02: true + 2026-03: true + 2026-04: true + 2026-05: true + 2026-06: true + 2026-07: true + 2026-08: true + 2026-09: true + 2026-10: true + 2026-11: true + 2026-12: true + takes_up_ssi_if_eligible: + '2026': true + pre_subsidy_rent: + '2026': 4800 + ct_ssp_lives_with_others: + 2026-01: true + 2026-02: true + 2026-03: true + 2026-04: true + 2026-05: true + 2026-06: true + 2026-07: true + 2026-08: true + 2026-09: true + 2026-10: true + 2026-11: true + 2026-12: true + spm_units: + unit: + members: + - person1 + - person2 + heating_type: + '2026': NATURAL_GAS + gas_expense: + '2026': 1000 + heat_expense_included_in_rent: + '2026': false + households: + household: + members: + - person1 + - person2 + state_code: + '2026': CT + tax_units: + tax1: + members: + - person1 + tax2: + members: + - person2 + marital_units: + marital1: + members: + - person1 + marital2: + members: + - person2 + families: + family1: + members: + - person1 + family2: + members: + - person2 + output: + ct_ceap_household_size: 1 + ct_ceap_countable_income: 100000 + ct_ceap_categorically_eligible: false + ct_ceap_eligible: false + ct_ceap: 0 diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py index f5e5a7fe847..2f8d2543194 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py @@ -16,6 +16,12 @@ def formula(spm_unit, period, parameters): person = spm_unit.members member = ~person("is_in_foster_care", period.first_month) ssi = spm_unit.sum(member * person("ssi", period, options=[ADD])) - receipt = add(spm_unit, period, ["snap", "ct_tfa", "ct_ssp"]) + ssi > 0 + # Remove SSP attributable to excluded foster members from the + # household receipt, preserving a supplied household SSP total. + excluded_ssp = spm_unit.sum( + ~member * person("ct_ssp_person", period, options=[ADD]) + ) + ssp = max_(spm_unit("ct_ssp", period, options=[ADD]) - excluded_ssp, 0) + receipt = add(spm_unit, period, ["snap", "ct_tfa"]) + ssi + ssp > 0 heat_in_rent = spm_unit("heat_expense_included_in_rent", period) return receipt & ~heat_in_rent diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py b/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py index b57e8b2bf66..ddadf887ee2 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py @@ -18,4 +18,8 @@ def formula(spm_unit, period, parameters): max_(size, 1), group, period, parameters, year_lag=p.fpg_year_lag ) income = spm_unit("ct_ceap_countable_income", period) - return p.income_level.calc(income / guideline, right=True) + level = p.income_level.calc(income / guideline, right=True) + # Categorical households above the SMI ceiling receive Level 3 even + # when large-family FPG thresholds would put them in a higher tier. + limit = spm_unit("ct_ceap_income_limit", period) + return where(income > limit, 3, level) From cf0834843b5ccc21a93d638b2ad78d0c7c74bacf Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 20:18:38 -0400 Subject: [PATCH 3/7] Count recurring retirement-account income in Connecticut CEAP --- .../ct/dss/ceap/income/sources/unearned.yaml | 3 ++ .../gov/states/ct/dss/ceap/ct_ceap.yaml | 22 ++++++++++++++ .../ceap/income/ct_ceap_countable_income.yaml | 29 +++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml index 94090e9eec9..cae9593991f 100644 --- a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml @@ -5,6 +5,9 @@ values: - unemployment_compensation - strike_benefits - pension_income + # Ongoing IRA/401k distributions are separate from pension_income. + # Existing annual inputs do not identify an excluded one-time lump sum. + - retirement_distributions - survivor_benefits - workers_compensation - disability_benefits diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml index 8d85b5e0e29..d40c581e6b4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml @@ -2166,3 +2166,25 @@ ct_ceap_categorically_eligible: false ct_ceap_eligible: false ct_ceap: 0 + +# Recurring IRA receipts exceed the published one-person income ceiling. +- name: Recurring IRA income above the limit prevents regular heating assistance. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person: + age: 70 + immigration_status: CITIZEN + taxable_ira_distributions: 100_000 + spm_units: + spm_unit: + members: [person] + heating_type: NATURAL_GAS + gas_expense: 1_000 + households: + household: + members: [person] + state_code: CT + output: + ct_ceap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml index 0a472d76736..812b4e39a7c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml @@ -376,3 +376,32 @@ state_code: CT output: ct_ceap_countable_income: 10_000 + +# Ongoing retirement receipts: pension 1,000 + taxable IRA 12,000 + exempt IRA 3,000. +# Count the two aggregates once; one-time lump sums are not represented here. +- name: Recurring taxable and exempt retirement distributions count beside pensions. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person: + age: 70 + immigration_status: CITIZEN + ssi: 0 + pension_income: 1_000 + taxable_ira_distributions: 12_000 + tax_exempt_ira_distributions: 3_000 + spm_units: + spm_unit: + members: [person] + heating_type: NATURAL_GAS + gas_expense: 1_000 + snap: 0 + ct_tfa: 0 + ct_ssp: 0 + households: + household: + members: [person] + state_code: CT + output: + ct_ceap_countable_income: 16_000 From 9058eeadf0412600056afcfa820ea01e7e34e70a Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 20:39:09 -0400 Subject: [PATCH 4/7] Clarify Connecticut retirement income source comment --- .../gov/states/ct/dss/ceap/income/sources/unearned.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml index cae9593991f..806ab64f8ae 100644 --- a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml @@ -6,7 +6,7 @@ values: - strike_benefits - pension_income # Ongoing IRA/401k distributions are separate from pension_income. - # Existing annual inputs do not identify an excluded one-time lump sum. + # Include taxable and exempt account distributions once. - retirement_distributions - survivor_benefits - workers_compensation From 9a9beb01edd24962f06c614f4d8fd6355b6287dd Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 2 Nov 2026 11:53:58 -0500 Subject: [PATCH 5/7] Apply Wave 2C sweep and review fixes Co-Authored-By: Claude Opus 5.5 --- .../ct/dss/ceap/eligibility/smi_rate.yaml | 2 +- .../ceap/income/earned_income_min_age.yaml | 6 +- .../ct/dss/ceap/income/sources/earned.yaml | 4 +- .../ct/dss/ceap/income/sources/unearned.yaml | 11 +- policyengine_us/programs.yaml | 2 +- .../gov/states/ct/dss/ceap/ct_ceap.yaml | 143 +++++++++++++++++- .../ct_ceap_categorically_eligible.yaml | 35 +++++ .../eligibility/ct_ceap_household_member.yaml | 28 ++++ .../eligibility/ct_ceap_household_size.yaml | 2 +- .../ceap/income/ct_ceap_countable_income.yaml | 64 +++++++- .../gov/states/ct/dss/ceap/ct_ceap.py | 5 +- .../ct_ceap_categorically_eligible.py | 11 +- .../eligibility/ct_ceap_household_member.py | 17 +++ .../eligibility/ct_ceap_household_size.py | 7 +- .../ceap/income/ct_ceap_countable_income.py | 15 +- .../dss/ceap/payment/ct_ceap_benefit_level.py | 8 +- source_conflicts/candidates.yaml | 30 ++++ 17 files changed, 350 insertions(+), 40 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_member.yaml create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_member.py diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml index 71bb510e033..31a08a89f90 100644 --- a/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/eligibility/smi_rate.yaml @@ -9,5 +9,5 @@ metadata: reference: - title: Connecticut FY2026 LIHEAP State Plan, Section 2.1 href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=9 - - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Section V + - title: Connecticut approved FY2027 LIHEAP Allocation Plan, Section IV.B href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/earned_income_min_age.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/earned_income_min_age.yaml index 96c3abbd5f4..2013508846c 100644 --- a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/earned_income_min_age.yaml +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/earned_income_min_age.yaml @@ -7,7 +7,5 @@ metadata: period: year label: Connecticut CEAP minimum age for earned income reference: - - title: "Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 #page 6-7" - href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6 - - title: "Connecticut approved FY2027 LIHEAP Allocation Plan, Sections III-V #page 5-9" - href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 + - title: "Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 #page 5-7" + href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml index 0e9d1bc8c49..d5e15cebd18 100644 --- a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml @@ -12,7 +12,7 @@ metadata: period: year label: Connecticut CEAP countable earned income sources reference: - - title: "Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 #page 6-7" - href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6 + - title: "Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 #page 5-7" + href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=5 - title: "Connecticut approved FY2027 LIHEAP Allocation Plan, Sections III-V #page 5-9" href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml index f9e5017ee60..7feb41aa506 100644 --- a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml @@ -5,7 +5,9 @@ values: - total_unemployment_compensation - strike_benefits - pension_income - - military_retirement_pay + # Military retirement includes Survivor Benefit Plan annuities. + - military_retirement_income + - railroad_benefits # Ongoing IRA/401k distributions are separate from pension_income. # Include taxable and exempt account distributions once. - retirement_distributions @@ -21,6 +23,9 @@ values: - child_support_received - financial_assistance - gambling_winnings + # The residual input for the plan's one-time lump sums, jury duty, legal + # settlements and insurance payments; it may hold other receipts. + - miscellaneous_income - veterans_benefits metadata: @@ -28,7 +33,7 @@ metadata: period: year label: Connecticut CEAP countable unearned income sources reference: - - title: "Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 #page 6-7" - href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6 + - title: "Connecticut FY2026 LIHEAP State Plan, Section 1.8-1.9 #page 5-7" + href: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=5 - title: "Connecticut approved FY2027 LIHEAP Allocation Plan, Sections III-V #page 5-9" href: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index f103afcfd00..e281438f4fb 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -967,7 +967,7 @@ programs: variable: ct_ceap parameter_prefix: gov.states.ct.dss.ceap verified_years: "2026-2027" - notes: Regular basic and rental heating assistance, including the federal income floor, Social Security net of Part B premiums and take-up-gated TFA categorical receipt. Annual income and primary-fuel expenses approximate application income and covered-season costs; rental inputs stand in for nonnegative gross receipts. Detailed household exclusions, VA pension subtypes and prior awards are not fully represented. The separate nominal SNAP grant, crisis assistance and equipment are outside this implementation. + notes: FY2026-FY2027 basic and rental heating assistance. The SNAP nominal benefit, crisis, weatherization and equipment assistance are out of scope. # --- SSA programs --- - id: ssi diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml index d8bd266ae05..78a65881089 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml @@ -1613,7 +1613,7 @@ # C1: 10 * 13,600 = 136,000 > floor(91,854 * 1.47) = 135,025; # categorical level 3 basic 295 + vulnerable 50 = 345 (not FPG level 2). # C3: foster SSI/SSP excluded; remaining member income 100,000 > 47,764. -- name: Above-SMI categorical large household receives level 3 +- name: Case 41, above-SMI categorical large household receives level 3. period: 2026 absolute_error_margin: 0.01 input: @@ -2050,7 +2050,7 @@ ct_ceap_benefit_level: 3 ct_ceap: 345 -- name: Excluded foster adult SSP cannot establish categorical eligibility +- name: Case 42, excluded foster adult SSP cannot establish categorical eligibility. period: 2026 absolute_error_margin: 0.01 input: @@ -2173,23 +2173,23 @@ ct_ceap: 0 # Recurring IRA receipts exceed the published one-person income ceiling. -- name: Recurring IRA income above the limit prevents regular heating assistance. +- name: Case 43, recurring IRA income above the limit prevents regular heating assistance. period: 2026 absolute_error_margin: 0.01 input: people: - person: + person1: age: 70 immigration_status: CITIZEN taxable_ira_distributions: 100_000 spm_units: spm_unit: - members: [person] + members: [person1] heating_type: NATURAL_GAS gas_expense: 1_000 households: household: - members: [person] + members: [person1] state_code: CT output: ct_ceap: 0 @@ -2697,3 +2697,134 @@ ct_ceap_benefit_level: [1, 1] ct_ceap_eligible: [true, false] ct_ceap: [655, 0] + +# Allocation plans: rental benefits apply when heat is in rent and carry no bill +# cap, so a $50 gas bill does not limit the Level 1 FY2026 amount of $125. +- name: Case 51, a rental benefit is not capped by a reported bill. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 50 + heat_expense_included_in_rent: true + snap: 0 + tanf: 0 + ct_ssp: 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_benefit_level: 1 + ct_ceap: 125 + +# 2025 guideline for 11 members: 15,650 + 10 x 5,500 = 70,650. Income of exactly +# floor(91,854 x 1.47) = 135,025 is not above the limit, so the ratio sets the +# level: 135,025 / 70,650 = 1.91, Level 2, $445. Case 41 is above the limit. +- name: Case 52, a categorical household exactly at the limit keeps its poverty level. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0, employment_income: 135_025} + person2: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person3: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person4: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person5: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person6: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person7: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person8: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person9: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person10: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + person11: {age: 40, immigration_status: CITIZEN, ssi: 0, social_security: 0} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + heating_type: NATURAL_GAS + gas_expense: 1_000 + snap: 1_200 + tanf: 0 + ct_ssp: 0 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + state_code: CT + output: + ct_ceap_income_limit: 135_025 + ct_ceap_categorically_eligible: true + ct_ceap_benefit_level: 2 + ct_ceap: 445 + +# Allocation plans p. 5: households do not include incarcerated individuals. +# First unit: size 1, 55,000 is above the 47,764 limit and the 17,215 floor, and +# the incarcerated member's SSI establishes no categorical receipt: $0. Second +# unit: 25,000 / 15,650 = 1.60, Level 2, $445; the incarcerated member's wages +# and age 65 count for neither income nor vulnerability. +- name: Case 53, incarcerated members are outside size income vulnerability and categorical receipt. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + employment_income: 55_000 + person2: + age: 40 + immigration_status: CITIZEN + is_incarcerated: + 2026-01: true + ssi: 1_200 + social_security: 0 + person3: + age: 40 + immigration_status: CITIZEN + ssi: 0 + social_security: 0 + employment_income: 25_000 + person4: + age: 65 + immigration_status: CITIZEN + is_incarcerated: + 2026-01: true + ssi: 0 + social_security: 0 + employment_income: 10_000 + spm_units: + spm_unit1: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + snap: 0 + tanf: 0 + ct_ssp: 0 + spm_unit2: + members: [person3, person4] + heating_type: NATURAL_GAS + gas_expense: 1_000 + snap: 0 + tanf: 0 + ct_ssp: 0 + households: + household1: + members: [person1, person2] + state_code: CT + household2: + members: [person3, person4] + state_code: CT + output: + ct_ceap_household_size: [1, 1] + ct_ceap_countable_income: [55_000, 25_000] + ct_ceap_categorically_eligible: [false, false] + ct_ceap: [0, 445] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml index f104ba4ad25..646fa290284 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml @@ -352,3 +352,38 @@ state_code: CT output: ct_ceap_categorically_eligible: false + +# REQ-006: reported SSI receipt establishes categorical receipt when the +# modeled SSI amount is zero. +- name: Case 11, reported SSI receipt with direct heating. + period: 2026 + input: + people: + person1: + age: 70 + immigration_status: CITIZEN + is_in_foster_care: + 2026-01: false + ssi: + '2026': 0 + receives_ssi: + 2026-01: true + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: + '2026': 0 + tanf: + '2026': 0 + ct_ssp: + '2026': 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_categorically_eligible: true + diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_member.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_member.yaml new file mode 100644 index 00000000000..c9586bbf631 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_member.yaml @@ -0,0 +1,28 @@ +# PDF page 5 +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 + +- name: Case 1, foster and incarcerated people are outside the household. + period: 2026 + input: + people: + person1: + age: 40 + person2: + age: 10 + is_in_foster_care: + 2026-01: true + person3: + age: 40 + is_incarcerated: + 2026-01: true + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + gas_expense: 1_000 + households: + household: + members: [person1, person2, person3] + state_code: CT + output: + ct_ceap_household_member: [true, false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml index ded8059a0d7..fde01588aa9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml @@ -154,7 +154,7 @@ '2026': 0 social_security: 0 person2: - age: 38 + age: 10 immigration_status: CITIZEN is_disabled: false is_in_foster_care: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml index b69e00f025e..2802790f2cd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml @@ -382,12 +382,12 @@ # Ongoing retirement receipts: pension 1,000 + taxable IRA 12,000 + exempt IRA 3,000. # Count the two aggregates once; one-time lump sums are not represented here. -- name: Recurring taxable and exempt retirement distributions count beside pensions. +- name: Case 10, recurring taxable and exempt retirement distributions count beside pensions. period: 2026 absolute_error_margin: 0.01 input: people: - person: + person1: age: 70 immigration_status: CITIZEN ssi: 0 @@ -396,7 +396,7 @@ tax_exempt_ira_distributions: 3_000 spm_units: spm_unit: - members: [person] + members: [person1] heating_type: NATURAL_GAS gas_expense: 1_000 snap: 0 @@ -404,7 +404,63 @@ ct_ssp: 0 households: household: - members: [person] + members: [person1] state_code: CT output: ct_ceap_countable_income: 16_000 + +# Plan item 1.9 counts retirement and pension benefits: railroad retirement 6,000. +- name: Case 11, railroad retirement counts as a retirement benefit. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + immigration_status: CITIZEN + ssi: 0 + railroad_benefits: 6_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + snap: 0 + tanf: 0 + ct_ssp: 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 6_000 + +# Plan 1.9 (p. 6) checks one-time lump sums, jury duty, legal settlements and +# insurance payments, which miscellaneous_income carries: 30,000 + 20,000 = +# 50,000, above the 47,764 one-person limit and the 17,215 floor. +- name: Case 12, miscellaneous income counts toward the income limit. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + ssi: 0 + employment_income: 30_000 + miscellaneous_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + snap: 0 + tanf: 0 + ct_ssp: 0 + households: + household: + members: [person1] + state_code: CT + output: + ct_ceap_countable_income: 50_000 + ct_ceap: 0 diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py b/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py index 79314095f64..b66a4ef0431 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py @@ -18,8 +18,9 @@ def formula(spm_unit, period, parameters): level = max_(spm_unit("ct_ceap_benefit_level", period), 1) person = spm_unit.members age = person("age", period) - qualified = person("is_citizen_or_legal_immigrant", period) - qualified = qualified & ~person("is_in_foster_care", period.first_month) + qualified = person("is_citizen_or_legal_immigrant", period) & person( + "ct_ceap_household_member", period + ) vulnerable = spm_unit.any( qualified & ( diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py index 03f57ea3d0e..ada48e48e81 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py @@ -15,14 +15,19 @@ def formula(spm_unit, period, parameters): # Refugee Cash Assistance and means-tested VA receipt are unavailable; # generic veterans_benefits does not establish VA eligibility. person = spm_unit.members - member = ~person("is_in_foster_care", period.first_month) + member = person("ct_ceap_household_member", period) ssi = spm_unit.sum(member * person("ssi", period, options=[ADD])) - # Remove SSP attributable to excluded foster members from the + # Remove SSP attributable to members outside the household from the # household receipt, preserving a supplied household SSP total. excluded_ssp = spm_unit.sum( ~member * person("ct_ssp_person", period, options=[ADD]) ) ssp = max_(spm_unit("ct_ssp", period, options=[ADD]) - excluded_ssp, 0) - receipt = add(spm_unit, period, ["snap", "tanf"]) + ssi + ssp > 0 + reported_ssi = spm_unit.any( + member & (add(person, period, ["receives_ssi"]) > 0) + ) + receipt = (add(spm_unit, period, ["snap", "tanf"]) + ssi + ssp > 0) | ( + reported_ssi + ) heat_in_rent = spm_unit("heat_expense_included_in_rent", period) return receipt & ~heat_in_rent diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_member.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_member.py new file mode 100644 index 00000000000..4a17fb1f944 --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_member.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ct_ceap_household_member(Variable): + value_type = bool + entity = Person + label = "Connecticut CEAP household member" + definition_period = YEAR + defined_for = StateCode.CT + reference = "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5" + + def formula(person, period, parameters): + # Households exclude incarcerated people and foster children or adults. + # January status stands in for status at application. Boarders and + # residents of institutions of higher learning have no input. + month = period.first_month + return ~person("is_in_foster_care", month) & ~person("is_incarcerated", month) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.py index fbf71a97b9a..ead6ca9ba51 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.py @@ -9,11 +9,10 @@ class ct_ceap_household_size(Variable): defined_for = StateCode.CT # PDF pages 5,9 reference = "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5" - # The SPM unit approximates the common energy household. Boarders and other - # institutional residents need additional household-construction facts. + # The SPM unit approximates the common energy household. def formula(spm_unit, period, parameters): person = spm_unit.members qualified = person("is_citizen_or_legal_immigrant", period) - foster = person("is_in_foster_care", period.first_month) - return spm_unit.sum(qualified & ~foster) + member = person("ct_ceap_household_member", period) + return spm_unit.sum(qualified & member) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py b/policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py index eadaf2c2c11..58834cf3e25 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py @@ -20,10 +20,14 @@ def formula(spm_unit, period, parameters): person = spm_unit.members # Annual inputs approximate the permitted 52-week assessment. Existing # net business inputs are used without further business-cost deductions. - earned = sum(max_(person(source, period), 0) for source in p.sources.earned) + earned = 0 + for source in p.sources.earned: + earned = earned + max_(person(source, period), 0) adult = person("age", period) >= p.earned_income_min_age - member = ~person("is_in_foster_care", period.first_month) - unearned = sum(max_(person(source, period), 0) for source in p.sources.unearned) + member = person("ct_ceap_household_member", period) + unearned = 0 + for source in p.sources.unearned: + unearned = unearned + max_(person(source, period), 0) social_security = max_( person("social_security", period) - person("medicare_part_b_premium", period), @@ -32,9 +36,8 @@ def formula(spm_unit, period, parameters): # Nonqualified members' income counts in full. SSI, TFA and general # assistance are excluded by the model plan's income checklist. # Rental inputs stand in for nonnegative gross receipts. Excluded VA - # pension subtypes, gross rental receipts, - # in-kind support and separately identified jury/settlement/insurance/ - # AmeriCorps receipts cannot be resolved by these existing income inputs. + # pension subtypes, in-kind support and AmeriCorps payments cannot be + # resolved by these existing income inputs. return spm_unit.sum( member * (where(adult, earned, 0) + unearned + social_security) ) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py b/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py index bb8422ca1c2..3d145325b15 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py @@ -20,8 +20,10 @@ def formula(spm_unit, period, parameters): ) income = spm_unit("ct_ceap_countable_income", period) level = p.income_level.calc(income / guideline, right=True) - # Categorical households above the SMI ceiling receive Level 3 even - # when large-family FPG thresholds would put them in a higher tier. + # Categorical households above the SMI ceiling receive the last level + # (201% FPG to 60% SMI) even when large-family FPG thresholds would put + # them in a higher tier. + lowest_level = p.income_level.amounts[-1] limit = spm_unit("ct_ceap_income_limit", period) categorical = spm_unit("ct_ceap_categorically_eligible", period) - return where(categorical & (income > limit), 3, level) + return where(categorical & (income > limit), lowest_level, level) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 7d8c41658c6..6238b5d789b 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -1136,6 +1136,36 @@ candidates: state: ruled note: 'Ruled in October 2026 to follow the statute; verify the applicable regulation version. Code not yet on main: co premium assistance formula, aca_ptc_slcsp.' +- id: us-ct:liheap-income-floor-vs-smi-limit + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Can Connecticut's 60% SMI CEAP limit exclude a very large household whose income is below the federal 110% + poverty-guideline floor? + sources: + - kind: statute + citation: 42 U.S.C. 8624(b)(2)(B) + url: https://www.law.cornell.edu/uscode/text/42/8624#b_2_B + - kind: plan + citation: Connecticut approved FFY2027 LIHEAP Allocation Plan, section IV.B, p.7 + url: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7 + readings: + statute: Income below 110% of the poverty guideline cannot by itself exclude the household. + other: The 60% SMI limit falls below that floor from 29 members in FY2026 and 28 in FY2027. + example: Thirty people with $190,000 exceed the $187,382 FY2026 limit but are below the $192,665 floor (2025 + guideline, one-year lag), so they keep the Level 1 basic benefit of $595. + pe_us: + follows: statute + code: + - policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py + - policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml + - policyengine_us/parameters/gov/states/ct/dss/ceap/payment/fpg_year_lag.yaml + state: unreviewed + note: PE-US applies the floor, rounded to cents with the statute's strict "less than" (ct_ceap_eligible.py). A + categorical household above the limit gets Level 3 under the benefit matrix note, so those thirty people get $295 + with SNAP and $595 without. - id: us-dc:eitc-no-tin-child-schedule-before-2023 program: income-tax years: From 252e211901ee0c9f4703f25766ac533d826104ed Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 3 Nov 2026 16:43:07 -0500 Subject: [PATCH 6/7] Apply review fixes to Connecticut CEAP Co-Authored-By: Claude Opus 5.5 --- .../ct/dss/ceap/income/sources/earned.yaml | 2 + policyengine_us/programs.yaml | 16 +- .../gov/states/ct/dss/ceap/ct_ceap.yaml | 196 ++++++++++++++---- .../ct_ceap_categorically_eligible.yaml | 23 +- .../ceap/eligibility/ct_ceap_eligible.yaml | 27 ++- .../eligibility/ct_ceap_household_size.yaml | 12 +- .../eligibility/ct_ceap_income_eligible.yaml | 16 ++ .../eligibility/ct_ceap_income_limit.yaml | 8 +- .../ceap/income/ct_ceap_countable_income.yaml | 23 +- .../ceap/payment/ct_ceap_benefit_level.yaml | 8 +- .../gov/states/ct/dss/ceap/ct_ceap.py | 2 +- .../ct_ceap_categorically_eligible.py | 4 +- .../dss/ceap/eligibility/ct_ceap_eligible.py | 15 +- .../eligibility/ct_ceap_income_eligible.py | 27 +++ .../dss/ceap/payment/ct_ceap_benefit_level.py | 23 +- source_conflicts/candidates.yaml | 41 +++- 16 files changed, 315 insertions(+), 128 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.yaml create mode 100644 policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.py diff --git a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml index d5e15cebd18..3017bd3887c 100644 --- a/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml +++ b/policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml @@ -2,6 +2,8 @@ description: Connecticut counts these earned income sources under the Connecticu values: 2025-10-01: - employment_income + # Enter basic pay here or in employment_income, not both. + - military_basic_pay - self_employment_income - sstb_self_employment_income - farm_operations_income diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index e5e1803571a..6a38a298c22 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1020,6 +1020,14 @@ programs: parameter_prefix: gov.states.az.des.liheap verified_years: "2026" notes: FY2026 Standard benefit covering heating and cooling bills from the point-based benefit matrix. Crisis assistance, water for evaporative cooling and weatherization are out of scope. + - state: CT + status: partial + name: Connecticut CEAP + full_name: Connecticut Energy Assistance Program + variable: ct_ceap + parameter_prefix: gov.states.ct.dss.ceap + verified_years: "2026-2027" + notes: FY2026-FY2027 basic and rental heating assistance. The SNAP nominal benefit, crisis, weatherization and equipment assistance are out of scope. - state: GA status: partial name: Georgia LIHEAP @@ -1314,14 +1322,6 @@ programs: parameter_prefix: gov.states.wy.dfs.lieap verified_years: "2026" notes: FY2026 regular heating from the published fuel cost standards. Crisis, cooling, weatherization and equipment assistance are out of scope. - - state: CT - status: partial - name: Connecticut CEAP - full_name: Connecticut Energy Assistance Program - variable: ct_ceap - parameter_prefix: gov.states.ct.dss.ceap - verified_years: "2026-2027" - notes: FY2026-FY2027 basic and rental heating assistance. The SNAP nominal benefit, crisis, weatherization and equipment assistance are out of scope. # --- SSA programs --- - id: ssi diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml index 78a65881089..eb13cb68b3b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/ct_ceap.yaml @@ -1,4 +1,4 @@ -# REQ-001-011. Independent end-to-end source scenarios; no CEAP intermediates supplied as inputs. +# Independent end-to-end source scenarios; no CEAP intermediates supplied as inputs. # Sources: # - https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf # PDF pages 5-7 @@ -6,7 +6,7 @@ # PDF pages 5-7,9-11,15 # - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 # - https://www.law.cornell.edu/uscode/text/42/8624#b_2_B -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 1, FY2026 level 1 direct heating grant. period: 2026 absolute_error_margin: 0.01 @@ -45,7 +45,7 @@ ct_ceap_eligible: true ct_ceap: 595 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 2, FY2026 level 1 rental grant. period: 2026 absolute_error_margin: 0.01 @@ -84,7 +84,7 @@ ct_ceap_eligible: true ct_ceap: 125 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 3, FY2026 level 2 direct heating grant. period: 2026 absolute_error_margin: 0.01 @@ -123,7 +123,7 @@ ct_ceap_eligible: true ct_ceap: 445 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 4, FY2026 level 2 rental grant. period: 2026 absolute_error_margin: 0.01 @@ -162,7 +162,7 @@ ct_ceap_eligible: true ct_ceap: 100 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 5, FY2026 level 3 direct heating grant. period: 2026 absolute_error_margin: 0.01 @@ -201,7 +201,7 @@ ct_ceap_eligible: true ct_ceap: 295 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 6, FY2026 level 3 rental grant. period: 2026 absolute_error_margin: 0.01 @@ -240,7 +240,7 @@ ct_ceap_eligible: true ct_ceap: 75 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 7, FY2027 level 1 direct heating grant. period: 2027 absolute_error_margin: 0.01 @@ -279,7 +279,7 @@ ct_ceap_eligible: true ct_ceap: 655 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 8, FY2027 level 1 rental grant. period: 2027 absolute_error_margin: 0.01 @@ -318,7 +318,7 @@ ct_ceap_eligible: true ct_ceap: 140 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 9, FY2027 level 2 direct heating grant. period: 2027 absolute_error_margin: 0.01 @@ -357,7 +357,7 @@ ct_ceap_eligible: true ct_ceap: 505 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 10, FY2027 level 2 rental grant. period: 2027 absolute_error_margin: 0.01 @@ -396,7 +396,7 @@ ct_ceap_eligible: true ct_ceap: 115 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 11, FY2027 level 3 direct heating grant. period: 2027 absolute_error_margin: 0.01 @@ -435,7 +435,7 @@ ct_ceap_eligible: true ct_ceap: 355 -# REQ-007/008/011: published basic or rental amount; direct annual expense 1,000 exceeds schedule. +# Published basic or rental amount; direct annual expense 1,000 exceeds schedule. - name: Case 12, FY2027 level 3 rental grant. period: 2027 absolute_error_margin: 0.01 @@ -474,7 +474,7 @@ ct_ceap_eligible: true ct_ceap: 90 -# REQ-007: age 60 meets elderly boundary; Level 1 basic plus 50. +# Age 60 meets elderly boundary; Level 1 basic plus 50. - name: Case 13, FY2026 elderly member receives fifty dollar supplement. period: 2026 absolute_error_margin: 0.01 @@ -508,7 +508,7 @@ output: ct_ceap: 645 -# REQ-007: age 60 meets elderly boundary; Level 1 basic plus 50. +# Age 60 meets elderly boundary; Level 1 basic plus 50. - name: Case 14, FY2027 elderly member receives fifty dollar supplement. period: 2027 absolute_error_margin: 0.01 @@ -542,7 +542,7 @@ output: ct_ceap: 705 -# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +# Vulnerability is a household condition, with one 50 dollar add-on. - name: Case 15, age just below sixty is not elderly. period: 2026 absolute_error_margin: 0.01 @@ -576,7 +576,7 @@ output: ct_ceap: 595 -# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +# Vulnerability is a household condition, with one 50 dollar add-on. - name: Case 16, disabled adult receives vulnerability supplement. period: 2026 absolute_error_margin: 0.01 @@ -610,7 +610,7 @@ output: ct_ceap: 645 -# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +# Vulnerability is a household condition, with one 50 dollar add-on. - name: Case 17, child just below six receives vulnerability supplement. period: 2026 absolute_error_margin: 0.01 @@ -653,7 +653,7 @@ output: ct_ceap: 645 -# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +# Vulnerability is a household condition, with one 50 dollar add-on. - name: Case 18, child at six no longer supplies young child supplement. period: 2026 absolute_error_margin: 0.01 @@ -696,7 +696,7 @@ output: ct_ceap: 595 -# REQ-007: vulnerability is a household condition, with one 50 dollar add-on. +# Vulnerability is a household condition, with one 50 dollar add-on. - name: Case 19, multiple vulnerable members receive one supplement. period: 2026 absolute_error_margin: 0.01 @@ -739,7 +739,7 @@ output: ct_ceap: 645 -# REQ-008: rental Level 1 is 125, no 50 dollar supplement and no exclusion based only on housing assistance. +# Rental Level 1 is 125, no 50 dollar supplement and no exclusion based only on housing assistance. - name: Case 20, vulnerable subsidized rental household receives rental amount only. period: 2026 absolute_error_margin: 0.01 @@ -774,7 +774,7 @@ output: ct_ceap: 125 -# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +# Retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. - name: Case 21, gas bill below schedule caps retained grant. period: 2026 absolute_error_margin: 0.01 @@ -808,7 +808,7 @@ output: ct_ceap: 100 -# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +# Retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. - name: Case 22, gas bill exactly at schedule pays full amount. period: 2026 absolute_error_margin: 0.01 @@ -842,7 +842,7 @@ output: ct_ceap: 595 -# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +# Retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. - name: Case 23, gas bill above schedule does not increase grant. period: 2026 absolute_error_margin: 0.01 @@ -876,7 +876,7 @@ output: ct_ceap: 595 -# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +# Retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. - name: Case 24, fuel oil selects oil expense not larger gas bill. period: 2026 absolute_error_margin: 0.01 @@ -911,7 +911,7 @@ output: ct_ceap: 100 -# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +# Retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. - name: Case 25, electric heating uses pre subsidy electricity expense. period: 2026 absolute_error_margin: 0.01 @@ -946,7 +946,7 @@ output: ct_ceap: 200 -# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +# Retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. - name: Case 26, wood heating uses wood expense. period: 2026 absolute_error_margin: 0.01 @@ -981,7 +981,7 @@ output: ct_ceap: 300 -# REQ-009: retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. +# Retained direct award = smaller of regular schedule and nonnegative primary-fuel cost. - name: Case 27, no direct heating expense yields no benefit. period: 2026 absolute_error_margin: 0.01 @@ -1015,7 +1015,7 @@ output: ct_ceap: 0 -# REQ-006/007: positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. +# Positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. - name: Case 28, snap receipt bypasses income ceiling but retains level three. period: 2026 absolute_error_margin: 0.01 @@ -1053,7 +1053,7 @@ ct_ceap_benefit_level: 3 ct_ceap: 295 -# REQ-006/008: rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. +# Rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. - name: Case 29, snap does not bypass rental income ceiling. period: 2026 absolute_error_margin: 0.01 @@ -1090,7 +1090,7 @@ ct_ceap_eligible: false ct_ceap: 0 -# REQ-006/007: positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. +# Positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. - name: Case 30, TFA receipt bypasses income ceiling but retains level three. period: 2026 absolute_error_margin: 0.01 @@ -1137,7 +1137,7 @@ ct_ceap_benefit_level: 3 ct_ceap: 295 -# REQ-006/008: rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. +# Rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. - name: Case 31, TFA does not bypass rental income ceiling. period: 2026 absolute_error_margin: 0.01 @@ -1183,7 +1183,7 @@ ct_ceap_eligible: false ct_ceap: 0 -# REQ-006/007: positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. +# Positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. - name: Case 32, ssi receipt bypasses income ceiling but retains level three. period: 2026 absolute_error_margin: 0.01 @@ -1221,7 +1221,7 @@ ct_ceap_benefit_level: 3 ct_ceap: 345 -# REQ-006/008: rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. +# Rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. - name: Case 33, ssi does not bypass rental income ceiling. period: 2026 absolute_error_margin: 0.01 @@ -1258,7 +1258,7 @@ ct_ceap_eligible: false ct_ceap: 0 -# REQ-006/007: positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. +# Positive receipt represents application receipt; above-limit income still sets Level 3, with vulnerability where applicable. - name: Case 34, ct_ssp receipt bypasses income ceiling but retains level three. period: 2026 absolute_error_margin: 0.01 @@ -1296,7 +1296,7 @@ ct_ceap_benefit_level: 3 ct_ceap: 345 -# REQ-006/008: rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. +# Rental aid keeps the 60% SMI ceiling; separate 20.01 SNAP nominal payment is outside scope. - name: Case 35, ct_ssp does not bypass rental income ceiling. period: 2026 absolute_error_margin: 0.01 @@ -1333,7 +1333,7 @@ ct_ceap_eligible: false ct_ceap: 0 -# REQ-001/007: size 1, income 20,000 gives Level 2; qualified young child adds 50 to 445. +# Size 1, income 20,000 gives Level 2; qualified young child adds 50 to 445. - name: Case 36, citizen child with nonqualified parent uses child size and all income. period: 2026 absolute_error_margin: 0.01 @@ -1381,7 +1381,7 @@ ct_ceap_benefit_level: 2 ct_ceap: 495 -# REQ-001/007: excluded elder is not a member for vulnerability. +# Excluded elder is not a member for vulnerability. - name: Case 37, nonqualified elder does not establish vulnerability. period: 2026 absolute_error_margin: 0.01 @@ -1425,7 +1425,7 @@ ct_ceap_household_size: 1 ct_ceap: 595 -# REQ-001: removing foster child excludes 30,000 unearned income and young-child supplement; remaining adult gets Level 2 basic 445. +# Removing foster child excludes 30,000 unearned income and young-child supplement; remaining adult gets Level 2 basic 445. - name: Case 38, represented foster child excluded from income size and vulnerability. period: 2026 absolute_error_margin: 0.01 @@ -1472,7 +1472,7 @@ ct_ceap_benefit_level: 2 ct_ceap: 445 -# REQ-001/011: each SPM unit belongs to its own state household; all CT variables are state-guarded. +# Each SPM unit belongs to its own state household; all CT variables are state-guarded. - name: Case 39, mixed state batch isolates Connecticut calculation. period: 2026 absolute_error_margin: 0.01 @@ -1558,7 +1558,7 @@ ct_ceap_benefit_level: [1, 0, 0] ct_ceap: [595, 0, 0] -# REQ-001/006: represented foster members are outside the energy household. +# Represented foster members are outside the energy household. # The adult has 100,000 countable income and no qualifying receipt of their own. - name: Case 40, represented foster SSI does not establish categorical receipt. period: 2026 @@ -2828,3 +2828,117 @@ ct_ceap_countable_income: [55_000, 25_000] ct_ceap_categorically_eligible: [false, false] ct_ceap: [0, 445] + +- name: Case 54, a categorical household the federal floor admits keeps its FY2026 income level. + period: 2026 + absolute_error_margin: 0.01 + # 2025 FPG for 30 = 175_150; 110% = 192_665; SMI limit = 187_382 (Case 44). + # The floor admits 190_000 without SNAP, so 42 U.S.C. 8624(b)(5) bars paying + # less because of SNAP: 190_000 / 175_150 = 1.08, Level 1, min(595, 1_000) = 595. + input: + people: + person1: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0, employment_income: 190_000} + person2: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person3: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person4: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person5: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person6: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person7: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person8: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person9: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person10: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person11: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person12: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person13: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person14: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person15: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person16: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person17: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person18: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person19: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person20: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person21: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person22: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person23: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person24: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person25: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person26: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person27: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person28: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person29: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person30: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15, person16, person17, person18, person19, person20, person21, person22, person23, person24, person25, person26, person27, person28, person29, person30] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: 1_200 + tanf: 0 + ct_ssp: 0 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15, person16, person17, person18, person19, person20, person21, person22, person23, person24, person25, person26, person27, person28, person29, person30] + state_code: CT + output: + ct_ceap_household_size: 30 + ct_ceap_categorically_eligible: true + ct_ceap_income_eligible: true + ct_ceap_benefit_level: 1 + ct_ceap: 595 + +- name: Case 55, a categorical household the federal floor admits keeps its FY2027 income level. + period: 2027 + absolute_error_margin: 0.01 + # 2026 FPG for 28 = 15_960 + 27 x 5_680 = 169_320; 110% = 186_252; SMI limit = + # floor(93_681 x 1.98) = 185_488. 186_000 / 169_320 = 1.10, Level 1, + # min(655, 1_000) = 655. + input: + people: + person1: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0, employment_income: 186_000} + person2: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person3: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person4: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person5: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person6: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person7: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person8: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person9: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person10: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person11: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person12: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person13: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person14: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person15: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person16: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person17: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person18: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person19: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person20: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person21: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person22: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person23: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person24: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person25: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person26: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person27: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + person28: {age: 40, immigration_status: CITIZEN, is_disabled: false, ssi: 0} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15, person16, person17, person18, person19, person20, person21, person22, person23, person24, person25, person26, person27, person28] + heating_type: NATURAL_GAS + gas_expense: 1_000 + heat_expense_included_in_rent: false + snap: 1_200 + tanf: 0 + ct_ssp: 0 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15, person16, person17, person18, person19, person20, person21, person22, person23, person24, person25, person26, person27, person28] + state_code: CT + output: + ct_ceap_household_size: 28 + ct_ceap_categorically_eligible: true + ct_ceap_income_eligible: true + ct_ceap_benefit_level: 1 + ct_ceap: 655 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml index 646fa290284..0960c55841b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.yaml @@ -1,10 +1,10 @@ -# REQ-006. P26 physical p5; A26/A27 IV and IX direct-vendor exception. +# FY2026 plan page 5; FY2026 and FY2027 allocation plans, sections IV and IX; direct-vendor exception. # Sources: # PDF pages 5-7 # - https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=5 # PDF pages 5-7,9-11,15 # - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 -# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +# Direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. - name: Case 1, snap receipt with direct heating. period: 2026 input: @@ -37,7 +37,7 @@ output: ct_ceap_categorically_eligible: true -# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +# Direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. - name: Case 2, snap receipt with heat included in rent. period: 2026 input: @@ -70,7 +70,7 @@ output: ct_ceap_categorically_eligible: false -# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +# Direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. - name: Case 3, TFA receipt with direct heating. period: 2026 input: @@ -112,7 +112,7 @@ output: ct_ceap_categorically_eligible: true -# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +# Direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. - name: Case 4, TFA receipt with heat included in rent. period: 2026 input: @@ -154,7 +154,7 @@ output: ct_ceap_categorically_eligible: false -# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +# Direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. - name: Case 5, ssi receipt with direct heating. period: 2026 input: @@ -187,7 +187,7 @@ output: ct_ceap_categorically_eligible: true -# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +# Direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. - name: Case 6, ssi receipt with heat included in rent. period: 2026 input: @@ -220,7 +220,7 @@ output: ct_ceap_categorically_eligible: false -# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +# Direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. - name: Case 7, ct_ssp receipt with direct heating. period: 2026 input: @@ -253,7 +253,7 @@ output: ct_ceap_categorically_eligible: true -# REQ-006: direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. +# Direct-vendor receipt bypasses the income ceiling; rental assistance keeps its income test. - name: Case 8, ct_ssp receipt with heat included in rent. period: 2026 input: @@ -286,7 +286,6 @@ output: ct_ceap_categorically_eligible: false -# REQ-006. - name: Case 9, no qualifying receipt has no categorical exception. period: 2026 input: @@ -319,7 +318,7 @@ output: ct_ceap_categorically_eligible: false -# REQ-004/006: generic VA does not identify the required means-tested program. +# Generic VA does not identify the required means-tested program. - name: Case 10, generic veterans benefits do not establish categorical receipt. period: 2026 input: @@ -353,7 +352,7 @@ output: ct_ceap_categorically_eligible: false -# REQ-006: reported SSI receipt establishes categorical receipt when the +# Reported SSI receipt establishes categorical receipt when the # modeled SSI amount is zero. - name: Case 11, reported SSI receipt with direct heating. period: 2026 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.yaml index 70e1ae49635..4adfef6a5b0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.yaml @@ -1,9 +1,9 @@ -# REQ-001/005/006/008/009. State, membership, income and heating responsibility. +# State, membership, income and heating responsibility. # Sources: # - https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf # PDF pages 5-7,9-11,15 # - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 -# REQ-005: published one-person SMI ceiling is inclusive. +# Published one-person SMI ceiling is inclusive. - name: Case 1, FY2026 income at ceiling eligible. period: 2026 input: @@ -37,7 +37,7 @@ output: ct_ceap_eligible: true -# REQ-005: published one-person SMI ceiling is inclusive. +# Published one-person SMI ceiling is inclusive. - name: Case 2, FY2026 income one cent over ceiling ineligible. period: 2026 input: @@ -71,7 +71,7 @@ output: ct_ceap_eligible: false -# REQ-005: published one-person SMI ceiling is inclusive. +# Published one-person SMI ceiling is inclusive. - name: Case 3, FY2027 income at ceiling eligible. period: 2027 input: @@ -105,7 +105,7 @@ output: ct_ceap_eligible: true -# REQ-005: published one-person SMI ceiling is inclusive. +# Published one-person SMI ceiling is inclusive. - name: Case 4, FY2027 income one cent over ceiling ineligible. period: 2027 input: @@ -139,7 +139,7 @@ output: ct_ceap_eligible: false -# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +# Heating responsibility gate, with heat-in-rent exception to direct expense evidence. - name: Case 5, known direct fuel with positive matching cost. period: 2026 input: @@ -172,7 +172,7 @@ output: ct_ceap_eligible: true -# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +# Heating responsibility gate, with heat-in-rent exception to direct expense evidence. - name: Case 6, direct fuel with zero matching cost. period: 2026 input: @@ -205,7 +205,7 @@ output: ct_ceap_eligible: false -# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +# Heating responsibility gate, with heat-in-rent exception to direct expense evidence. - name: Case 7, direct fuel with negative matching cost. period: 2026 input: @@ -238,7 +238,7 @@ output: ct_ceap_eligible: false -# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +# Heating responsibility gate, with heat-in-rent exception to direct expense evidence. - name: Case 8, affirmative no heating despite reported bills. period: 2026 input: @@ -271,7 +271,7 @@ output: ct_ceap_eligible: false -# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +# Heating responsibility gate, with heat-in-rent exception to direct expense evidence. - name: Case 9, unknown direct fuel does not establish a heating bill. period: 2026 input: @@ -304,7 +304,7 @@ output: ct_ceap_eligible: false -# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +# Heating responsibility gate, with heat-in-rent exception to direct expense evidence. - name: Case 10, rental with unknown fuel and no separate cost. period: 2026 input: @@ -337,7 +337,7 @@ output: ct_ceap_eligible: true -# REQ-008/009: heating responsibility gate, with heat-in-rent exception to direct expense evidence. +# Heating responsibility gate, with heat-in-rent exception to direct expense evidence. - name: Case 11, rental with affirmative no heat. period: 2026 input: @@ -370,7 +370,7 @@ output: ct_ceap_eligible: false -# REQ-001/006: categorical receipt does not waive qualified membership. +# Categorical receipt does not waive qualified membership. - name: Case 12, no qualified members ineligible despite SNAP receipt. period: 2026 input: @@ -403,7 +403,6 @@ output: ct_ceap_eligible: false -# REQ-006/009. - name: Case 13, categorical receipt does not waive heating responsibility. period: 2026 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml index fde01588aa9..19f6232ca94 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_household_size.yaml @@ -1,10 +1,10 @@ -# REQ-001. A26/A27 III and V.J-K; qualified membership and represented foster exclusion. +# FY2026 and FY2027 allocation plans, sections III and V.J-K; qualified membership and represented foster exclusion. # Sources: # PDF pages 5,9 # - https://www.cga.ct.gov/app/related/20250616_2025%20Block%20Grants%20and%20Waiver%20Applications/FFY%202026%20LIHEAP%20Allocation%20Plan.pdf#page=5 # PDF pages 5-7,9-11,15 # - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 -# REQ-001: count qualified members, excluding represented foster members. +# Count qualified members, excluding represented foster members. - name: Case 1, citizen and qualified noncitizens count. period: 2026 input: @@ -55,7 +55,7 @@ output: ct_ceap_household_size: 3 -# REQ-001: count qualified members, excluding represented foster members. +# Count qualified members, excluding represented foster members. - name: Case 2, undocumented parent does not count but citizen child does. period: 2026 input: @@ -97,7 +97,7 @@ output: ct_ceap_household_size: 1 -# REQ-001: count qualified members, excluding represented foster members. +# Count qualified members, excluding represented foster members. - name: Case 3, all nonqualified members yield zero size. period: 2026 input: @@ -139,7 +139,7 @@ output: ct_ceap_household_size: 0 -# REQ-001: count qualified members, excluding represented foster members. +# Count qualified members, excluding represented foster members. - name: Case 4, represented foster child is excluded. period: 2026 input: @@ -181,7 +181,7 @@ output: ct_ceap_household_size: 1 -# REQ-001: count qualified members, excluding represented foster members. +# Count qualified members, excluding represented foster members. - name: Case 5, eight qualified household members count. period: 2026 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.yaml new file mode 100644 index 00000000000..38ccf38cdb3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.yaml @@ -0,0 +1,16 @@ +# Income test before categorical receipt. +# Sources: +# - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7 +# - https://www.law.cornell.edu/uscode/text/42/8624#b_2_B +# The one-person limit is inclusive at 47,764. For 30 people the limit is 187,382 +# and the floor is 1.1 x 175,150 = 192,665, with a strict "below". +- name: Case 1, the limit is inclusive and the federal floor is strict. + period: 2026 + input: + state_code: [CT, CT, CT, CT, CT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000] + ct_ceap_household_size: [1, 1, 30, 30, 30] + ct_ceap_countable_income: [47_764, 47_764.01, 187_382.01, 192_664.99, 192_665] + output: + ct_ceap_income_eligible: [true, false, true, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.yaml index f0e8ccfe3fd..3e721064bd5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_limit.yaml @@ -1,9 +1,9 @@ -# REQ-005. M26 and A27 physical p7 published annual income ceilings. +# FY2026 benefit matrix and FY2027 allocation plan page 7; published annual income ceilings. # Sources: # - https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf # PDF pages 5-7,9-11,15 # - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 -# REQ-005: source table amounts, not values evaluated from the model formula. +# Source table amounts, not values evaluated from the model formula. - name: Case 1, all eight published FY2026 household income limits. period: 2026 absolute_error_margin: 0.01 @@ -16,7 +16,7 @@ output: ct_ceap_income_limit: [47_764, 62_460, 77_157, 91_854, 106_550, 121_247, 124_002, 126_758] -# REQ-005: source table amounts, not values evaluated from the model formula. +# Source table amounts, not values evaluated from the model formula. - name: Case 2, all eight published FY2027 household income limits. period: 2027 absolute_error_margin: 0.01 @@ -29,7 +29,7 @@ output: ct_ceap_income_limit: [48_714, 63_703, 78_692, 93_681, 108_669, 123_658, 126_469, 129_279] -# REQ-001/005: eligibility requires a positive qualified household size. +# Eligibility requires a positive qualified household size. - name: Case 3, no qualified members have no income allowance. period: 2026 absolute_error_margin: 0.01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml index 2802790f2cd..e844872a70e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.yaml @@ -1,4 +1,4 @@ -# REQ-001-004. P26 physical pp6-7 checkbox source list; A26/A27 III. +# FY2026 plan pages 6-7 check-box source list; FY2026 and FY2027 allocation plans, section III. # Sources: # PDF pages 5-7 # - https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=5 @@ -6,7 +6,7 @@ # - https://www.cga.ct.gov/app/related/20250616_2025%20Block%20Grants%20and%20Waiver%20Applications/FFY%202026%20LIHEAP%20Allocation%20Plan.pdf#page=5 # PDF pages 5-7,9-11,15 # - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 -# REQ-002: 1,000 + 2,000 + 3,000 + 4,000 + 5,000 = 15,000. +# 1,000 + 6,000 + 2,000 + 3,000 + 4,000 + 5,000 = 21,000. - name: Case 1, adult earned sources all count. period: 2026 absolute_error_margin: 0.01 @@ -22,6 +22,7 @@ '2026': 0 social_security: 0 employment_income: 1_000 + military_basic_pay: 6_000 self_employment_income: 2_000 sstb_self_employment_income: 3_000 farm_operations_income: 4_000 @@ -43,9 +44,9 @@ members: [person1] state_code: CT output: - ct_ceap_countable_income: 15_000 + ct_ceap_countable_income: 21_000 -# REQ-003/004: 100 + 200 + ... + 1,700 = 15,300. Generic VA is countable under the documented input limitation. +# 100 + 200 + ... + 1,700 = 15,300. Generic VA is countable under the documented input limitation. - name: Case 2, supported disjoint unearned sources count once. period: 2026 absolute_error_margin: 0.01 @@ -95,7 +96,7 @@ output: ct_ceap_countable_income: 15_300 -# REQ-003: 1,200 taxable + 300 exempt pension = 1,500, without counting the aggregate twice. +# 1,200 taxable + 300 exempt pension = 1,500, without counting the aggregate twice. - name: Case 3, pension components aggregate once. period: 2026 absolute_error_margin: 0.01 @@ -131,7 +132,7 @@ output: ct_ceap_countable_income: 1_500 -# REQ-002/003: 10,000 adult wages + 1,000 child Social Security + 2,000 child support = 13,000. +# 10,000 adult wages + 1,000 child Social Security + 2,000 child support = 13,000. - name: Case 4, child earned income excluded but unearned retained. period: 2026 absolute_error_margin: 0.01 @@ -178,7 +179,7 @@ output: ct_ceap_countable_income: 13_000 -# REQ-002: 20,000 + 1,000 earned and 3,000 unearned = 24,000 at age 18. +# 20,000 + 1,000 earned and 3,000 unearned = 24,000 at age 18. - name: Case 5, earned income counts at age eighteen. period: 2026 absolute_error_margin: 0.01 @@ -215,7 +216,7 @@ output: ct_ceap_countable_income: 24_000 -# REQ-002: 10,000 wages + 2,000 SSTB + 1,000 partnership = 13,000; losses contribute zero. +# 10,000 wages + 2,000 SSTB + 1,000 partnership = 13,000; losses contribute zero. - name: Case 6, business losses do not offset other earnings. period: 2026 absolute_error_margin: 0.01 @@ -254,7 +255,7 @@ output: ct_ceap_countable_income: 13_000 -# REQ-003: P26 countable-income checklist leaves SSI, TANF and general assistance unchecked. +# The FY2026 plan's countable-income checklist leaves SSI, TANF and general assistance unchecked. - name: Case 7, SSI TFA and general assistance excluded. period: 2026 absolute_error_margin: 0.01 @@ -290,7 +291,7 @@ output: ct_ceap_countable_income: 1_000 -# REQ-001: all 20,000 of excluded-from-size parent wages plus 1,000 child support counts. +# All 20,000 of excluded-from-size parent wages plus 1,000 child support counts. - name: Case 8, nonqualified members income fully counts. period: 2026 absolute_error_margin: 0.01 @@ -335,7 +336,7 @@ output: ct_ceap_countable_income: 21_000 -# REQ-001: foster member is outside the energy household, including the members 8,000 unearned income. +# Foster member is outside the energy household, including the members 8,000 unearned income. - name: Case 9, represented foster income excluded. period: 2026 absolute_error_margin: 0.01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.yaml index 98c6ea56f00..979f3eba992 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.yaml @@ -1,9 +1,9 @@ -# REQ-007/011. M26 and A27 pp7,10-11; prior-year FPG thresholds. +# FY2026 benefit matrix and FY2027 allocation plan pages 7,10-11; prior-year FPG thresholds. # Sources: # - https://liheapch.acf.gov/docs/2026/benefits-matricies/CT_BenefitMatrix_Heat-Crisis_2026.pdf # PDF pages 5-7,9-11,15 # - https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 -# REQ-007/011: prior-year FPG; 125% boundary 19,562.50, 200% boundary 31,300.00. +# Prior-year FPG; 125% boundary 19,562.50, 200% boundary 31,300.00. - name: Case 1, FY2026 inclusive poverty boundaries and no gaps. period: 2026 input: @@ -16,7 +16,7 @@ output: ct_ceap_benefit_level: [1, 1, 1, 2, 2, 2, 3, 3] -# REQ-007/011: prior-year FPG; 125% boundary 19,950.00, 200% boundary 31,920.00. +# Prior-year FPG; 125% boundary 19,950.00, 200% boundary 31,920.00. - name: Case 2, FY2027 inclusive poverty boundaries and no gaps. period: 2027 input: @@ -29,7 +29,7 @@ output: ct_ceap_benefit_level: [1, 1, 1, 2, 2, 2, 3, 3] -# REQ-007: 2025 two-person FPG is 15,650 + 5,500 = 21,150; multiply by 1.25 and 2. +# 2025 two-person FPG is 15,650 + 5,500 = 21,150; multiply by 1.25 and 2. - name: Case 3, two person family uses additional person FPG. period: 2026 input: diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py b/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py index b66a4ef0431..59728e202fc 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/ct_ceap.py @@ -33,7 +33,7 @@ def formula(spm_unit, period, parameters): # Utility credits exceeding covered-season charges must be returned; # delivered-fuel payments cover actual deliveries. Annual primary-fuel # expense approximates covered-season cost and oil vendor pricing. - direct_payment = min_(basic, max_(spm_unit("heating_expense", period), 0)) + direct_payment = min_(basic, spm_unit("heating_expense", period)) heat_in_rent = spm_unit("heat_expense_included_in_rent", period) # Rental cash grants have no bill cap. Prior awards/moves, the separate # SNAP nominal payment, crisis, weatherization and equipment are excluded. diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py index ada48e48e81..8672b1e54b0 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_categorically_eligible.py @@ -18,7 +18,9 @@ def formula(spm_unit, period, parameters): member = person("ct_ceap_household_member", period) ssi = spm_unit.sum(member * person("ssi", period, options=[ADD])) # Remove SSP attributable to members outside the household from the - # household receipt, preserving a supplied household SSP total. + # household receipt, preserving a supplied household SSP total. The + # floor stops a supplied total below the excluded members' SSP from + # cancelling other receipt. excluded_ssp = spm_unit.sum( ~member * person("ct_ssp_person", period, options=[ADD]) ) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py index 82f43e9bb22..4587e68b5cb 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py @@ -1,5 +1,4 @@ from policyengine_us.model_api import * -from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class ct_ceap_eligible(Variable): @@ -16,17 +15,9 @@ class ct_ceap_eligible(Variable): def formula(spm_unit, period, parameters): size = spm_unit("ct_ceap_household_size", period) - income = spm_unit("ct_ceap_countable_income", period) - limit = spm_unit("ct_ceap_income_limit", period) - categorical = spm_unit("ct_ceap_categorically_eligible", period) - p = parameters(period).gov.states.ct.dss.ceap.payment - p_hhs = parameters(period).gov.hhs.liheap - state_group = spm_unit.household("state_group_str", period) - guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) - # Preserve the published ceiling and the strict federal protection - # where the SMI limit is lower for large households. - floor = np.round(guideline * p_hhs.fpg_floor, 2) - income_eligible = (income <= limit) | (income < floor) | categorical + income_eligible = spm_unit("ct_ceap_income_eligible", period) | spm_unit( + "ct_ceap_categorically_eligible", period + ) heat_in_rent = spm_unit("heat_expense_included_in_rent", period) expense = spm_unit("heating_expense", period) heating_type = spm_unit("heating_type", period) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.py b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.py new file mode 100644 index 00000000000..5ffbc2331b6 --- /dev/null +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class ct_ceap_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Connecticut CEAP income eligible without categorical receipt" + definition_period = YEAR + defined_for = StateCode.CT + reference = ( + "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7", + "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ct.dss.ceap.payment + p_hhs = parameters(period).gov.hhs.liheap + size = spm_unit("ct_ceap_household_size", period) + state_group = spm_unit.household("state_group_str", period) + guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + # Preserve the published ceiling and the strict federal protection + # where the SMI limit is lower for large households. + floor = np.round(guideline * p_hhs.fpg_floor, 2) + income = spm_unit("ct_ceap_countable_income", period) + limit = spm_unit("ct_ceap_income_limit", period) + return (income <= limit) | (income < floor) diff --git a/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py b/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py index 3d145325b15..fa25cbda36e 100644 --- a/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py +++ b/policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py @@ -8,22 +8,25 @@ class ct_ceap_benefit_level(Variable): label = "Connecticut CEAP benefit level" definition_period = YEAR defined_for = StateCode.CT - # PDF pages 7,10-11 - reference = "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7" + reference = ( + # PDF pages 7,10-11 + "https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=7", + "https://www.law.cornell.edu/uscode/text/42/8624#b_5", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ct.dss.ceap.payment size = spm_unit("ct_ceap_household_size", period) group = spm_unit.household("state_group_str", period) - guideline = fpg( - max_(size, 1), group, period, parameters, year_lag=p.fpg_year_lag - ) + guideline = fpg(size, group, period, parameters, year_lag=p.fpg_year_lag) income = spm_unit("ct_ceap_countable_income", period) level = p.income_level.calc(income / guideline, right=True) - # Categorical households above the SMI ceiling receive the last level - # (201% FPG to 60% SMI) even when large-family FPG thresholds would put - # them in a higher tier. + # Categorical households that fail the income test receive the last + # level (201% FPG to 60% SMI) even when large-family FPG thresholds + # would put them in a higher tier. Households the income test admits, + # including through the federal floor, keep their level whether or not + # they are categorical: 42 U.S.C. 8624(b)(5) bars differentiating them. lowest_level = p.income_level.amounts[-1] - limit = spm_unit("ct_ceap_income_limit", period) categorical = spm_unit("ct_ceap_categorically_eligible", period) - return where(categorical & (income > limit), lowest_level, level) + income_eligible = spm_unit("ct_ceap_income_eligible", period) + return where(categorical & ~income_eligible, lowest_level, level) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 6c4d59c0678..2e990a6c1d6 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -1679,13 +1679,46 @@ candidates: pe_us: follows: statute code: - - policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_eligible.py + - policyengine_us/variables/gov/states/ct/dss/ceap/eligibility/ct_ceap_income_eligible.py + - policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py - policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml - policyengine_us/parameters/gov/states/ct/dss/ceap/payment/fpg_year_lag.yaml state: unreviewed - note: PE-US applies the floor, rounded to cents with the statute's strict "less than" (ct_ceap_eligible.py). A - categorical household above the limit gets Level 3 under the benefit matrix note, so those thirty people get $295 - with SNAP and $595 without. + note: PE-US applies the floor, rounded to cents with the statute's strict "less than" (ct_ceap_income_eligible.py). The + benefit matrix note's Level 3 reaches only categorical households the income test would deny. A categorical + household the floor admits keeps its income level, because 42 U.S.C. 8624(b)(5) bars differentiating between + (b)(2)(A) and (b)(2)(B) households, so those thirty people get $595 with or without SNAP. +- id: us-ct:liheap-plan-income-checklist + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Do SSI, TFA, general assistance, the State Supplement and a minor's earnings count for CEAP, as the allocation + plans' income definition can be read, or stay out, as the FY2026 plan's section 1.9 check boxes leave them? + sources: + - kind: plan + citation: Connecticut FY2026 LIHEAP State Plan, section 1.9, pp.6-7 + url: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6 + - kind: plan + citation: Connecticut approved FFY2027 LIHEAP Allocation Plan, section III, p.5 + url: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 + readings: + statute: No statute is supplied; plan 1.9 leaves SSI, General Assistance, TANF, "Other" and "Earned income of a child + under the age of 18" unchecked and does not name the State Supplement. + other: Section III of both allocation plans counts "Gross salaries/wages" with no age exception and "governmental + assistance not otherwise excluded as income". + example: A parent aged 40 with wages of $20,000 and a child aged 17 with wages of $8,000 is at 95% of the 2025 + guideline for two, Level 1 and $595, under plan 1.9, and at 132%, Level 2 and $445, if the child's wages count. + pe_us: + follows: gap-fill + code: + - policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml + - policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml + - policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py + state: unreviewed + note: PE-US follows plan 1.9, the specific list, and carries it into FY2027, which has no model plan. The State + Supplement stays out by the 2026-11-02 ruling; the other items have no ruling. - id: us-dc:eitc-no-tin-child-schedule-before-2023 program: income-tax years: From 2b51013d38f6ff298943bc95403688e4af4f3395 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 5 Nov 2026 13:20:12 -0500 Subject: [PATCH 7/7] Apply round 2 review fixes to Connecticut CEAP Co-Authored-By: Claude Opus 5.5 --- source_conflicts/candidates.yaml | 46 +++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index d3d06acc934..8e8629f06d0 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -1929,6 +1929,8 @@ candidates: - policyengine_us/variables/gov/states/ct/dss/ceap/payment/ct_ceap_benefit_level.py - policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml - policyengine_us/parameters/gov/states/ct/dss/ceap/payment/fpg_year_lag.yaml + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10611 state: unreviewed note: PE-US applies the floor, rounded to cents with the statute's strict "less than" (ct_ceap_income_eligible.py). The benefit matrix note's Level 3 reaches only categorical households the income test would deny. A categorical @@ -1940,8 +1942,8 @@ candidates: from: 2026 to: 2027 type: federal-fiscal - question: Do SSI, TFA, general assistance, the State Supplement and a minor's earnings count for CEAP, as the allocation - plans' income definition can be read, or stay out, as the FY2026 plan's section 1.9 check boxes leave them? + question: Do SSI, TFA, general assistance and a minor's earnings count for CEAP, as the allocation plans' income + definition can be read, or stay out, as the FY2026 plan's section 1.9 check boxes leave them? sources: - kind: plan citation: Connecticut FY2026 LIHEAP State Plan, section 1.9, pp.6-7 @@ -1950,8 +1952,8 @@ candidates: citation: Connecticut approved FFY2027 LIHEAP Allocation Plan, section III, p.5 url: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 readings: - statute: No statute is supplied; plan 1.9 leaves SSI, General Assistance, TANF, "Other" and "Earned income of a child - under the age of 18" unchecked and does not name the State Supplement. + plan: Plan 1.9 leaves SSI, General Assistance, TANF, "Other" and "Earned income of a child under the age of 18" + unchecked. other: Section III of both allocation plans counts "Gross salaries/wages" with no age exception and "governmental assistance not otherwise excluded as income". example: A parent aged 40 with wages of $20,000 and a child aged 17 with wages of $8,000 is at 95% of the 2025 @@ -1962,9 +1964,41 @@ candidates: - policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/earned.yaml - policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml - policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10611 state: unreviewed - note: PE-US follows plan 1.9, the specific list, and carries it into FY2027, which has no model plan. The State - Supplement stays out by the 2026-11-02 ruling; the other items have no ruling. + note: PE-US follows plan 1.9, the specific list, and carries it into FY2027, which has no model plan. +- id: us-ct:liheap-state-supplement-income + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Does the Connecticut State Supplement count as CEAP income under the allocation plans' governmental-assistance + clause, or stay out, with the FY2026 plan's section 1.9 "Other" box unchecked? + sources: + - kind: plan + citation: Connecticut FY2026 LIHEAP State Plan, section 1.9, pp.6-7 + url: https://liheapch.acf.gov/docs/2026/state-plans/CT_Plan_2026.pdf#page=6 + - kind: plan + citation: Connecticut approved FFY2027 LIHEAP Allocation Plan, section III, p.5 + url: https://portal.ct.gov/dss/-/media/departments-and-agencies/dss/winter-heating-assistance/09012026/ffy-27-liheap-allocation-plan.pdf#page=5 + readings: + plan: Plan 1.9 leaves General Assistance, SSI, TANF and "Other" unchecked and does not name the State Supplement. + other: Section III of both allocation plans counts "governmental assistance not otherwise excluded as income" and + does not name the State Supplement either. + example: A disabled person aged 50 with a pension of $18,000, a $2,400 State Supplement and a $1,000 gas bill is at 115% + of the 2025 guideline, Level 1 and $645, with the supplement out, and at 130%, Level 2 and $495, with it counted. + pe_us: + follows: gap-fill + code: + - policyengine_us/parameters/gov/states/ct/dss/ceap/income/sources/unearned.yaml + - policyengine_us/variables/gov/states/ct/dss/ceap/income/ct_ceap_countable_income.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10611 + state: ruled + note: 'Ruled 2026-11-02 by the PR author in the pre-filing review of this PR, item CT-S3: keep the State Supplement out + of countable income. Neither document names it, and plan 1.9 is the specific list.' - id: us-dc:eitc-no-tin-child-schedule-before-2023 program: income-tax years: